user2643469 user2643469 - 17 days ago 9
Node.js Question

Mongoose array elements ALL $in array

I have an array like this:

{
"_id" : ObjectId("581b7d650949a5204e0a6e9b"),
"types" : [
{
"type" : ObjectId("581b7c645057c4602f48627f"),
"quantity" : 4,
"_id" : ObjectId("581b7d650949a5204e0a6e9e")
},
{
"type" : ObjectId("581ca0e75b1e3058521a6d8c"),
"quantity" : 4,
"_id" : ObjectId("581b7d650949a5204e0a6e9e")
}
],
"__v" : 0
},
{
"_id" : ObjectId("581b7d650949a5204e0a6e9c"),
"types" : [
{
"type" : ObjectId("581b7c645057c4602f48627f"),
"quantity" : 4,
"_id" : ObjectId("581b7d650949a5204e0a6e9e")
}
],
"__v" : 0
}


And I want to create a query that will return me the elementswhere the array of types ALL match a $in array.

For example:

query([ObjectId("581b7c645057c4602f48627f"), ObjectId("581ca0e75b1e3058521a6d8c")])


should return elements 1 and 2

query([ObjectId("581b7c645057c4602f48627f")])


should return element 2

query([ObjectId("581ca0e75b1e3058521a6d8c")])


should return nothing

I tried

db.getCollection('elements').find({'types.type': { $in: [ObjectId("581ca0e75b1e3058521a6d8c")]}})


But it returns the elements if only one types matches

Answer

You may have to use aggregation as $in and $elematch will return matching. This unwinds types and groups them by id and then in the project stage does set equals to create a all match flag and matches in the last stage with true value.

aggregate([ {
    $project: {
        _id: 0,
        isAllMatch: {$setIsSubset: ["$types.type", [ObjectId("581b7c645057c4602f48627f")]]},
        data: "$$ROOT"
    }
}, {
    $match: {
        isAllMatch: true
    }
}])

Sample Output

{
    "isAllMatch": true,
    "data": {
        "_id": ObjectId("581b7d650949a5204e0a6e9c"),
        "types": [{
            "type": ObjectId("581b7c645057c4602f48627f"),
            "quantity": 4,
            "_id": ObjectId("581b7d650949a5204e0a6e9e")
        }],
        "__v": 0
    }
}

Alternative version:

aggregate([     
{
    "$redact": {
        "$cond": [
            { 
                "$eq": [
                    { $setIsSubset: ["$types.type", [ObjectId("581b7c645057c4602f48627f")]]}, 
                    true
                ]
            }, 
            "$$KEEP", 
            "$$PRUNE"
        ]
    }
}])
Comments