Reputation: 1345
Assume I have structure as;
{
"class" : "TESTCLASS",
"id" : "HyvF1sdZl",
"depends" : [
"S11T5ce",
"BytQLN6ml",
"Byzz8Ea7l",
"r1TUNX58x"
],
"list" : [
{
"class" : "DATA",
"id" : "H113d5Pwx"
},
{
"class" : "DATA",
"id" : "H113d5Pwx"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "DATA",
"id" : "H113d5Pwx"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "FDSAFAS",
"id" : "S11T5ce"
},
{
"class" : "YENITEST",
"id" : "r1TUNX58x"
},
{
"class" : "FDSAFAS",
"id" : "S11T5ce"
},
{
"class" : "CALENDAR",
"id" : "S11T5ce"
},
{
"class" : "EN",
"id" : "BytQLN6ml"
},
{
"class" : "CALENDAR",
"id" : "S11T5ce"
},
{
"class" : "EN_",
"id" : "Byzz8Ea7l"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "EN",
"id" : "BytQLN6ml"
},
{
"class" : "FDSAFAS",
"id" : "S11T5ce"
}
]
}
I want to project
list
items whose id
's are included in depends
array.
I mean, I only want to get;
"depends" : [
"S11T5ce",
"BytQLN6ml",
"Byzz8Ea7l",
"r1TUNX58x"
],
"list" : [
{
"class" : "FDSAFAS",
"id" : "S11T5ce"
},
{
"class" : "EN",
"id" : "BytQLN6ml"
},
{
"class" : "EN_",
"id" : "Byzz8Ea7l"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
}
]
To be able to do this I have written;
db.definition.aggregate([
{
$project: {
_id: 0,
depends :1,
depends: {$in: ["$list.id"]},
"list.defid": 1,
"list.class" :1,
}
}
]).pretty()
But this throws an error as "errmsg" : "Expression $in takes exactly 2 arguments. 1 were passed in."
What am I missing?
Upvotes: 2
Views: 2010
Reputation: 103305
With MongoDB 3.4 you could use the $addFields
pipeline to project other fields without explicitly naming them. As a single pipeline, use a combination of the $setUnion
, $filter
and $in
operators to return the desired
array. The $setUnion
operator helps with eliminating duplicates before applying the $filter
operator.
To follow the intuition, lets follow this example pipeline that just runs with the $filter
operator:
db.collection.aggregate([
{
"$addFields": {
"list": {
"$filter": {
"input": "$list",
"as": "item",
"cond": { "$in": ["$$item.id", "$depends"] }
}
}
}
}
])
Sample Output
{
"_id" : ObjectId("58d0e0d97a3871921504bb69"),
"class" : "TESTCLASS",
"id" : "HyvF1sdZl",
"depends" : [
"S11T5ce",
"BytQLN6ml",
"Byzz8Ea7l",
"r1TUNX58x"
],
"list" : [
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "FDSAFAS",
"id" : "S11T5ce"
},
{
"class" : "YENITEST",
"id" : "r1TUNX58x"
},
{
"class" : "FDSAFAS",
"id" : "S11T5ce"
},
{
"class" : "CALENDAR",
"id" : "S11T5ce"
},
{
"class" : "EN",
"id" : "BytQLN6ml"
},
{
"class" : "CALENDAR",
"id" : "S11T5ce"
},
{
"class" : "EN_",
"id" : "Byzz8Ea7l"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "EN",
"id" : "BytQLN6ml"
},
{
"class" : "FDSAFAS",
"id" : "S11T5ce"
}
]
}
With the $setUnion
operator, duplicates are eliminated first before applying $filter
as:
db.collection.aggregate([
{
"$addFields": {
"list": {
"$filter": {
"input": { "$setUnion": ["$list", []] },
"as": "item",
"cond": { "$in": ["$$item.id", "$depends"] }
}
}
}
}
])
Sample Output
{
"class" : "TESTCLASS",
"id" : "HyvF1sdZl",
"depends" : [
"S11T5ce",
"BytQLN6ml",
"Byzz8Ea7l",
"r1TUNX58x"
],
"list" : [
{
"class" : "FDSAFAS",
"id" : "S11T5ce"
},
{
"class" : "TEST",
"id" : "r1TUNX58x"
},
{
"class" : "YENITEST",
"id" : "r1TUNX58x"
},
{
"class" : "EN_",
"id" : "Byzz8Ea7l"
},
{
"class" : "CALENDAR",
"id" : "S11T5ce"
},
{
"class" : "EN",
"id" : "BytQLN6ml"
}
]
}
Upvotes: 2
Reputation: 122027
You can first use $project
and $filter
to filter out objects where id is not in depends
array but then to return unique objects by id and also include class is a bit of problem because if you use $addToSet
you can't specify fields that you want to make unique but ignore other fields in object or in this case class
in list.
db.col.aggregate([
{$project: {
depends: 1,
class: 1,
list: {
$filter: {
input: '$list',
as: 'item',
cond: {
$setIsSubset: [['$$item.id'], '$depends']
}
}
}
}},
{$unwind: '$list'},
{$group: {
_id: '$_id',
depends: {$first: '$depends'},
class: {$first: '$class'},
list: {
$addToSet: {
id: '$list.id',
class: '$list.class'
}
},
}}
])
The final result is this
[{
"_id": "58d0cea6aecf3102684e4f0e",
"depends": ["S11T5ce", "BytQLN6ml", "Byzz8Ea7l", "r1TUNX58x"],
"class": "TESTCLASS",
"list": [{
"id": "Byzz8Ea7l",
"class": "EN_"
}, {
"id": "BytQLN6ml",
"class": "EN"
}, {
"id": "S11T5ce",
"class": "FDSAFAS"
}, {
"id": "r1TUNX58x",
"class": "YENITEST"
}, {
"id": "S11T5ce",
"class": "CALENDAR"
}, {
"id": "r1TUNX58x",
"class": "TEST"
}]
}]
Upvotes: 1