spring-projects / spring-projects/spring-data-mongodb

Projection of fields in nested lists

Open
#4,428 6 comments 1 reaction 1 assignee View on GitHub

@christophstrobl is already working on this.

Since Jul 3, 2023.

type: enhancement
Dominant language
Java
Stars
1.7k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

Dear spring-data-mongodb maintenance team,
I am having trouble with the projection of fields in nested lists with spring-data-mongodb.

Given the following minimal example mongoDB:

db.nestedList.insertOne(
    {
      "flat": 1,
      "flatDescription": "one",
      "list": [
        {
          "element": 11,
          "description": "eleven"
        },
        {
          "element": 12,
          "description": "twelve"
        }
      ]
    }
 );
 db.nestedList.insertOne(
    {
      "flat": 2,
      "flatDescription": "two",
      "list": [
        {
          "element": 21,
          "description": "twentyone"
        },
        {
          "element": 22,
          "description": "twentytwo"
        }
      ]
    }
 );

Let's assume I only want to know about the fields "flat" and all "list.element". In mongoDB I can simply execute

db.nestedList
    .find({})
   .projection({ flat: 1, "list.element" : 1})

with the result

{
	"_id" : ObjectId("649a8045da17a6faee05e306"),
	"flat" : 1,
	"list" : [
		{
			"element" : 11
		},
		{
			"element" : 12
		}
	]
},

{
	"_id" : ObjectId("649a80a9da17a6faee05e307"),
	"flat" : 2,
	"list" : [
		{
			"element" : 21
		},
		{
			"element" : 22
		}
	]
}

This is exactly my expected and desired behavior!

Now my question is: How can I achieve this exact behavior with Spring Data (Java)?

The intuitive approach

ProjectionOperation projection = Aggregation.project("flat", "list.element");

generates

{ "flat" : "$flat", "element" : "$list.element"}

which produces

{
	"_id" : ObjectId("649a8045da17a6faee05e306"),
	"flat" : 1,
	"element" : [ 11, 12 ]
},
{
	"_id" : ObjectId("649a80a9da17a6faee05e307"),
	"flat" : 2,
	"element" : [ 21, 22 ]
}

which is obviously not what I need, as element is now a property in the root object and also is an array.

Slightly better

ProjectionOperation projection = Aggregation.project("flat");
projection = projection.and("list.element").as("list.element");

generates

{ "flat" : "$flat", "list.element" : "$list.element"}

which produces

{
	"_id" : ObjectId("649a8045da17a6faee05e306"),
	"list" : [
		{
			"element" : [ 11, 12 ]
		},
		{
			"element" : [ 11, 12 ]
		}
	],
	"flat" : 1
},
{
	"_id" : ObjectId("649a80a9da17a6faee05e307"),
	"list" : [
		{
			"element" : [ 21, 22 ]
		},
		{
			"element" : [ 21, 22 ]
		}
	],
	"flat" : 2
}

which is still wrong. At list the structure is correct now but list.element are still arrays.

I even tried

ProjectionOperation projection = Aggregation.project("flat");
projection = projection.and("list").nested(Fields.fields("list.element"));

generates

{ "_id" : "$_id", "list" : { "element" : "$list.element"}}

which produces

{
	"list" : [
		{
			"element" : [ 11, 12 ]
		},
		{
			"element" : [ 11, 12 ]
		}
	],
	"_id" : ObjectId("649a8045da17a6faee05e306")
},
{
	"list" : [
		{
			"element" : [ 21, 22 ]
		},
		{
			"element" : [ 21, 22 ]
		}
	],
	"_id" : ObjectId("649a80a9da17a6faee05e307")
}

which is still wrong as list.element are arrays.

Is this a bug or am I just using it wrong? In the latter case, can you please explain the proper usage? :)
I am looking forward to you response!

Kind regards,
fkreis

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.