0

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

2
  • why query([ObjectId("581ca0e75b1e3058521a6d8c")]) should return nothing ? Commented Nov 11, 2016 at 20:52
  • Because there is no element that has only the type ObjectId("581ca0e75b1e3058521a6d8c") Commented Nov 15, 2016 at 20:21

1 Answer 1

1

You may have to use aggregation as $in and $elematch will return only matching elements. 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:

This version combines both project and match stages into one $redact stage with $cond operator to decide whether to keep or prune the elements.

aggregate([{
    "$redact": {
        "$cond": [{
                $setIsSubset: ["$types.type", [ObjectId("581b7c645057c4602f48627f")]]
            },
            "$$KEEP",
            "$$PRUNE"
        ]
    }
}])
Sign up to request clarification or add additional context in comments.

9 Comments

I want to return elements, not types. And I think $setEquals will not work as I want to verify if all types in element are in the array given as a parameter.
it is returning element with types. you can pass any array to the isAllMatch in the group pipeline. please update your post with exactly you want to see the output and input you pass.
Thanks for the reply. $setEquals: ['$types.type', myTypes] doesn't seem to do the job. It's true only if '$types.type' as the same elements as myTypes. I want it to be true if ALL elements in $types.type are in myTypes. If $types.type = [1, 2] and myTypes = [1, 2, 3] I want to return the element. Right now, it doesn't return it
ah i see. that was never mentioned in the example you provided. let me see what i can do.
It works. Thanks a lot. Is there an elegant way to return the whole element instead of having to copy all subItem? My object is way more complex than in this sample and it seems painfull to have to copy everything...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.