1

Following is my Native MongoDB query and below is the SpringData Mongo API equivalent. I am getting struck on using $map in $project in SpringData Mongo API. Appreciate your help on completing my conversion to API

db.users.aggregate([    
    { $match: {$and : [{userType:"200"} },    
     { $unwind: "$userOrgMap" },
    {
      $lookup:
        {
          from: "users",
          localField: "userOrgMap.createdbyuser",
          foreignField: "_id",
          as: "created_by"
        }
   },
   {$project:{
       _id:"$_id",
       login:"$login",
       firstName:"$firstName",
       lastName:"$lastName",
       email:"$email",
       deactivateFlag:"$deactivateFlag",
       createdOn:"$createdOn",
       createdBy:{
        "$map": { 
                    "input": "$created_by", 
                    "as": "u", 
                      "in": { 
                          "name": { "$concat" : [ "$$u.firstName", " ", "$$u.lastName" ] }, 
                      } 
                }
    }
      }
    },
    { $sort : { createdBy : 1} }

])

Spring Query

 Aggregation aggregation = newAggregation(
            Aggregation.match(Criteria.where("userType").is(userType)),
            Aggregation.unwind("userOrgMap"),
            Aggregation.lookup("users", "userOrgMap.createdbyuser", "_id", "created_by"),
            Aggregation.project("userId","login","firstName","lastName","email","deactivateFlag","createdOn")
        );
2
  • Possible duplicate of Filter array in sub-document array field in Spring framework Commented May 13, 2017 at 11:22
  • Thanks for info. But I need some more help to figure out the API . My requirement is different. Aggregation.project("userId","login","firstName","lastName","email","deactivateFlag","createdOn") .and(mapItemsOf("created_by").as("u"). ??? )).as("createdBy") Commented May 13, 2017 at 11:40

2 Answers 2

4

You can try below $map aggregation.

  project().and(mapItemsOf("created_by").
                            as("u").
                            andApply(new AggregationExpression() {
                                @Override
                                public DBObject toDbObject(AggregationOperationContext aggregationOperationContext) {
                                    return new BasicDBObject("name", StringOperators.valueOf("u.firstName").concat(" ").concatValueOf("u.lastName").toDbObject(aggregationOperationContext));
                                }
                            }))
             .as("createdBy");

Using $let expression

 project().and(VariableOperators.Let.define(VariableOperators.Let.ExpressionVariable.newVariable("u").forExpression(ArrayOperators.arrayOf("created_by").elementAt(0))).
                            andApply(new AggregationExpression() {
                                @Override
                                public DBObject toDbObject(AggregationOperationContext aggregationOperationContext) {
                                    return new BasicDBObject("name", StringOperators.valueOf("u.firstName").concat(" ").concatValueOf("u.lastName").toDbObject(aggregationOperationContext));
                                }
                            }))
            .as("createdBy");

Use lambda and static imports.

import static org.springframework.data.mongodb.core.aggregation.ArrayOperators.arrayOf;
import static org.springframework.data.mongodb.core.aggregation.StringOperators.valueOf;
import static org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable.*;
import static org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.define;
import static org.springframework.data.mongodb.core.aggregation.VariableOperators.mapItemsOf;

project().and(mapItemsOf("created_by").
                as("u").
                andApply(aggregationOperationContext -> new BasicDBObject("name", valueOf("u.firstName").concat(" ").concatValueOf("u.lastName").toDbObject(aggregationOperationContext))))
                .as("createdBy");

    project().and(define(newVariable("u").forExpression(arrayOf("created_by").elementAt(0))).
            andApply(aggregationOperationContext -> new BasicDBObject("name", valueOf("u.firstName").concat(" ").concatValueOf("u.lastName").toDbObject(aggregationOperationContext))))
            .as("createdBy");
Sign up to request clarification or add additional context in comments.

14 Comments

Appreciate your quick reply.But I am getting "as" as undefined
Np. Updated answer to include the name alias for you to use map. I can't see anything in the api to provide the alias in the nested expression. So I have utilize BasicDBObject to create expression. You can do this with $let operator too by using $arrayElemAt and $concat.
Just realised that the result is not same for the created by. I am getting the following [{"userId":"249840105","login":"km993v","firstName":"Karthikeyan","lastName":"Maruthamuthu","createdOn":"2017-03-02 14:11:58.775","email":"[email protected]","deactivateFlag":false,"createdBy":"[ \"Chithra Nattamai Subburaman\"]"}] I am expecting the following "createdBy" : [ { "name" : "kaushik Mehta" } ]
Do you mean it is missing name field ? from the output ? Yes, I've mentioned that in my second comment. Please use the latest code. It will work.
My requirement is to have createdBy as an additional field with the concat of firstName and lastName. I heard of addField usage in aggregation. But not sure how to use it to achieve. If having createdBy is not possible without array, I am fine. But I don't want "[ \" from the output. Because in the output , I am getting "[" as a string value and not taken as array. I would prefer to get the same output as I got for my native query. Pls help
|
2

This is another approach I was able to do this.

Aggregation.project("userId","login","firstName","lastName","email","deactivateFlag","createdOn").and(VariableOperators.Map.itemsOf("created_by").as("u").andApply(StringOperators.Concat.valueOf("$$u.firstName").concat(" ").concatValueOf("$$u.lastName"))).as("createdBy");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.