'Query MongoDB for documents with non-empty intersection of arrays

So - I have a Heroku + Node + Express + MongoDB app in development, and I've been playing around all day trying to figure out how to get the mongo query I want. In a mongo collection, every document has a property 'fruits', which is an array of strings like

fruits : ['apple', 'orange', 'lemon']

The size and contents of fruits is arbitrary. I want to query the database for all documents whose fruits array has at least one element in common with another array which I provide when I make the query. How can I achieve this?

What I've tried so far centers around the $where query and some server-side JS. If I do something like

mongo.Db.connect(mongoUri, function(err, db) {
    db.collection('Users', function(er, collection) {           
        collection.find( {$where: 'false' } ).toArray(function(err, matches){

            console.log(matches)
            ...

        });
    });
});

I get an empty array - good! And if I change the false to true, I get the whole DB - also good! Things get less good with something like the following:

collection.find( {$where: function(){return false} } ).toArray(function(err, matches){...

I get the whole DB again! I thought this would pretty obviously return the same empty array as the very first example I gave above, as per the syntax presented at http://docs.mongodb.org/manual/reference/operator/query/where/

I was trying the above out just to see if I could get anything to work with $where, but further problems arise when I try to add server-side JS to the mix. I had a look at http://docs.mongodb.org/manual/tutorial/store-javascript-function-on-server/

and added the following to the system.js collection in my DB:

{
    "_id": "isMatch",
    "value": "function(){return false}"
}

and modified the above example with the line

collection.find( {$where: 'isMatch()' } ).toArray(function(err, matches){...

thinking that isMatch would now be in mongo's bag of tricks when it eval's the string (I assume it must be eval'ing the string), and the string syntax was the best bet from the playings around described above. Sadly this results in a console log of null - another flavour of wrong, I expected again an empty array.

Can anyone help me achieve the query I described above? I suspect I can work out the nitty gritty myself if you kind folks can help me understand 1. How to use the function syntax instead of the string syntax for $where, and 2. How to correctly declare a JS function in system.js for use with $where. Thanks in advance!



Solution 1:[1]

Your $where queries work fine when I try them in the shell, but you don't need to use $where for this query. Instead, you can use an $in that targets your fruits field to find docs that contain at least one matching fruit:

var fruits = ['apple', 'orange', 'lemon'];
db.test.find({fruits: {$in: fruits}});

Solution 2:[2]

Don't quite seem to know what was the case in 2013, but now I think you have to use $elemMatch along with $in that targets your fruits field to find docs that contain at least one matching fruit:

var fruits = ['apple', 'orange', 'lemon'];
db.test.find({fruits: {$elemMatch: {$in: fruits}}});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 JohnnyHK
Solution 2 Gniewko Ostrowski