nabiullinas
nabiullinas

Reputation: 1245

MongoDB. Find all document where element array have on of the needed element

I have mongodb documents

{
  "_id" : ObjectId("4e8ae86d08101908e1000001"),
  "name" : ["Some Name","Another"],
  "zipcode" : ["2223"]
}
{
  "_id" : ObjectId("4e8ae86d08101908e1000002"),
  "name" : ["Another", "Name"],
  "zipcode" : ["2224"]
}
{
  "_id" : ObjectId("4e8ae86d08101908e1000003"),
  "name" : ["Yet", "Another", "Name"],
  "zipcode" : ["2225"]
}

I need to find elements where "name array" have " Another ", "Name" values. I tried to use $in, but if there more values, like in

{
  "_id" : ObjectId("4e8ae86d08101908e1000003"),
  "name" : ["Yet", "Another", "Name"],
  "zipcode" : ["2225"]
}

It doesn't return it =(

Upvotes: 2

Views: 14123

Answers (2)

Neil Lunn
Neil Lunn

Reputation: 151170

The use of $in should be fine (as explained below) as long as your data is correct and the values do not contain any whitespace. But if they are not exactly the same you are going to need to do some $regex matching, also using the $and form:

db.collection.find({
    $and: [
       {name: {$regex: 'Another'} },
       {name: {$regex: 'Name'}} 
    ]
})

If you just want to get the one document that has both of, and only the fields values you want, and in the same order just supply the argument as an array:

db.collection.find({ name: ["Another", "Name" ] })

The usage of $in is to match any of the elements you supply as a list. In this case you would match all of your documents

db.collection.find({ name: {$in: [ "Another", "Name" ] } })

For the $all operator, it's function is to match all of elements contained in your argument list, so if an argument was not present in the array being searched it would not be included. So just the last two would match:

db.collection.find({ name: {$all: [ "Another", "Name" ] } })


{
  "_id" : ObjectId("4e8ae86d08101908e1000002"),
  "name" : ["Another", "Name"],
  "zipcode" : ["2224"]
}
{
  "_id" : ObjectId("4e8ae86d08101908e1000003"),
  "name" : ["Yet", "Another", "Name"],
  "zipcode" : ["2225"]
}

Finally, if you don't know the order of the elements you are matching, while a little contrived, aggregate gives you a way to get out of jail:

db.collection.aggregate([
    // Match using $all to reduce the list
    {$match: {name: {$all: ["Name","Another"] }}},

    // Keep the original document in the _id
    {$project:{ 
        _id: {
            _id: "$_id",
            name: "$name",
            zipcode: "$zipcode"
        },
        name: 1
    }},

    // Unwind the "name" array
    {$unwind: "$name"},


    // Count up the entries per _id
    {$group: { _id: "$_id", count: {$sum: 1}}},

    // Only match *2* as there were two elements we were expecting
    {$match: {count: 2} },

    // Project back to the original form
    {$project: { 
        _id:0,
        _id: "$_id._id",
         name: "$_id.name",
         zipcode: "$_id.zipcode"
     }} 
])

And that's all the forms I can think of.

Upvotes: 6

Yev
Yev

Reputation: 276

Have you looked at the MongoDB documentation for $in? Find it here

You'll need to do this:

find({name: { $in: [ "Another", "Name"] }})

Upvotes: 3

Related Questions