Reputation: 41
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.
Upvotes: 2
Views: 2789
Reputation: 75914
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"]
}
}]);
Upvotes: 1
Reputation: 3377
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.
Upvotes: 0