2

how i can find the document with $match on position 3 (only last item in array "ndr"). It is necessary that the aggreation search only in the last array-item of ndr.

 {
    "_id" : ObjectId("58bd5c63a3d24b4a2e4cde03"),
    "name" : "great document",
    "country" : "us_us",
    "cdate" : ISODate("2017-03-06T12:56:03.405Z"),
    "nodes" : [ 
        {
            "node" : 3244343,
            "name" : "Best Node ever",
            "ndr" : [ 
                {
                    "position" : 7,
                    "cdate" : ISODate("2017-03-06T10:55:20.000Z")
                }, 
                {
                    "position" : 3,
                    "cdate" : ISODate("2017-03-06T10:55:20.000Z")
                }
            ]
        }
    ],
}

I need this result after aggregation

{
    "name" : "great document",
    "country" : "us_us",
    "cdate" : ISODate("2017-03-06T12:56:03.405Z"),
    "nodes" : [ 
        {
            "node" : 3244343,
            "name" : "Best Node ever",
            "ndr" : [ 
                {
                    "position" : 3,
                    "cdate" : ISODate("2017-03-06T10:55:20.000Z")
                }
            ]
        }
    ]
}

I hope anyone can help me.

3
  • Hi Josch, and welcome to Stack Overflow. Can you edit your question to show what you've tried so far, and what's going wrong with it? Commented Mar 6, 2017 at 15:34
  • What's your MongoDB server version? Commented Mar 6, 2017 at 16:08
  • I have version MongoDB Version 3.4 Commented Mar 6, 2017 at 16:32

2 Answers 2

1

You can try below aggregation with Mongo 3.4 version.

The below query finds the last item (-1) using $arrayElemAt operator in the ndr array and stores the variable in last using $let operator for each nodes and compare the last variable position value using $$ notation to 3 and wraps the nbr element within array [] if entry found and else returns empty array.

$map operator to reach nbr array inside the nodes array and project the updated nbr array while mapping the rest of nodes fields.

$addFields stage will overwrite the existing nodes with new nodes while keeping the all the other fields.

db.collection.aggregate([{
    $addFields: {
        nodes: {
            $map: {
                input: "$nodes",
                as: "value",
                in: {
                    node: "$$value.node",
                    name: "$$value.name",
                    ndr: {
                        $let: {
                            vars: {
                                last: {
                                    $arrayElemAt: ["$$value.ndr", -1]
                                }
                            },
                            in: {
                                $cond: [{
                                        $eq: ["$$last.position", 3]
                                    },
                                    ["$$last"],
                                    []
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
}]);

Update:

You can try $redact which will keep the whole document if it finds the matching position from with the given filter.

$map to project the true, false values based on the filter for each of the nodes nbr position value and $anyElementTrue will inspect the previous boolean values for each doc and return a true or false value and $redact will use the booelan value from above comparison; true value to keep and false value to remove the document.

db.collection.aggregate([{
    $redact: {
        $cond: [{
            $anyElementTrue: {
                $map: {
                    input: "$nodes",
                    as: "value",
                    in: {
                        $let: {
                            vars: {
                                last: {
                                    $arrayElemAt: ["$$value.ndr", -1]
                                }
                            },
                            in: {
                                $cond: [{
                                        $eq: ["$$last.position", 3]
                                    },
                                    true,
                                    false
                                ]
                            }
                        }
                    }
                }
            }
        }, "$$KEEP", "$$PRUNE"]
    }
}]);
Sign up to request clarification or add additional context in comments.

2 Comments

Thx! how i can remove the whole document if not nodes.node.position matched with the given filter? At the moment the document would be in the pipeline.
Added a separate solution which will remove the document.
0

you will need to unwind both nested arrays.

 db.<collection>.aggregate([
      { $unwind: '$nodes' },
      { $unwind: '$nodes.ndr'},
      { $group: {'_id':{'_id':'$_id', 'nodeID', '$nodes.node' },
                 'name':{'$last':'$name'},
                 'country':{'$last':'$country'},
                 'cdate':{'$last':'$cdate'},
                 'nodes':{'$last':'$nodes'}
                }
      },
      { $match : { nodes.ndr.position: 3 } }
  ]);

From here you can reassemble the aggregate results with a $group on the and do a projection. I'm not sure what your ultimate end result should be.

8 Comments

and how i can search only in the last array item?
Sorry I thought you were looking for a specific value "position:3" if you need to find the last you will need to use a $group and $last docs.mongodb.com/manual/reference/operator/aggregation/last
Hi, i need to find the document which hast position 3 in the last array item
Ok I modified the answer to include a $group and $last, this groups by _id and nodes.node this should let you search just the last nodes.ndr off each nested set.
uhhh this works nearly perfect, but what when i have more than one node? at the moment their push the document twice with the different node matches. how i can group by document ID and push the second node into the node array?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.