Reputation: 23
I have the following schema:
{
"_id": 0,
"games": {
"gamesList": [
{
"franchiseName": "Tekken",
"genre": "Fighting",
"gamesInFranchise": [
{
"name": "Tekken 7",
"releaseDate": "03/18/2015",
"co-op": true,
"platforms": [
"playstation 3",
"xbox 360"
]
},
{
"name": "Tekken 6",
"releaseDate": "11/26/2007",
"co-op": true
},
{
"name": "Tekken 5",
"releaseDate": "01/01/2004",
"co-op": true
},
]
},
.................
]
}
}
I would like to filter documents based on specific "_id" that do not have the property "platforms". So essentially, the result would ideally look like this:
{
"_id": 0,
"games": {
"gamesList": [
{
"franchiseName": "Tekken",
"genre": "Fighting",
"gamesInFranchise": [
{
"name": "Tekken 6",
"releaseDate": "11/26/2007",
"co-op": true
},
{
"name": "Tekken 5",
"releaseDate": "01/01/2004",
"co-op": true
}
]
}
]
}
}
I tried using aggregation specifically with projection/filter query, but I can't seem to reach "platforms" to check if it exists or not.
Upvotes: 2
Views: 608
Reputation: 4363
The problem is that you have multiple embedded array before reaching platforms. You have to use the aggregation framework to deal with them.
Here's the query :
db.collection.aggregate([
{
$match: {
_id: 0
}
},
{
$addFields: {
"games.gamesList": {
$map: {
input: "$games.gamesList",
as: "franchise",
in: {
"franchiseName": "$$franchise.franchiseName",
"genre": "$$franchise.genre",
"gamesInFranchise": {
$filter: {
input: "$$franchise.gamesInFranchise",
as: "gameInFranchise",
cond: {
$eq: [
null,
{
$ifNull: [
"$$gameInFranchise.platforms",
null
]
}
]
}
}
}
}
}
}
}
}
])
I used $addFields to keep your other fields safe.
Note that you have to describe whole element in th 'in' field of '$map' operator.
The first $map operator is relative to the first level array, and $filter to the second level array.
$ifNull is the trick to check if element exists, or return something (here set to null). By checking the equality (or not equality) with null, you can check if the element exists
Upvotes: 4