Retrieve only the queried element in an object array in MongoDB collection











up vote
306
down vote

favorite
156














Suppose you have the following documents in my collection:



{  
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}




Do query:



db.test.find({"shapes.color": "red"}, {"shapes.color": 1})


Or



db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})




Returns matched document (Document 1), but always with ALL array items in shapes:



{ "shapes": 
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}


However, I'd like to get the document (Document 1) only with the array that contains color=red:



{ "shapes": 
[
{"shape": "circle", "color": "red"}
]
}


How can I do this?










share|improve this question




























    up vote
    306
    down vote

    favorite
    156














    Suppose you have the following documents in my collection:



    {  
    "_id":ObjectId("562e7c594c12942f08fe4192"),
    "shapes":[
    {
    "shape":"square",
    "color":"blue"
    },
    {
    "shape":"circle",
    "color":"red"
    }
    ]
    },
    {
    "_id":ObjectId("562e7c594c12942f08fe4193"),
    "shapes":[
    {
    "shape":"square",
    "color":"black"
    },
    {
    "shape":"circle",
    "color":"green"
    }
    ]
    }




    Do query:



    db.test.find({"shapes.color": "red"}, {"shapes.color": 1})


    Or



    db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})




    Returns matched document (Document 1), but always with ALL array items in shapes:



    { "shapes": 
    [
    {"shape": "square", "color": "blue"},
    {"shape": "circle", "color": "red"}
    ]
    }


    However, I'd like to get the document (Document 1) only with the array that contains color=red:



    { "shapes": 
    [
    {"shape": "circle", "color": "red"}
    ]
    }


    How can I do this?










    share|improve this question


























      up vote
      306
      down vote

      favorite
      156









      up vote
      306
      down vote

      favorite
      156






      156







      Suppose you have the following documents in my collection:



      {  
      "_id":ObjectId("562e7c594c12942f08fe4192"),
      "shapes":[
      {
      "shape":"square",
      "color":"blue"
      },
      {
      "shape":"circle",
      "color":"red"
      }
      ]
      },
      {
      "_id":ObjectId("562e7c594c12942f08fe4193"),
      "shapes":[
      {
      "shape":"square",
      "color":"black"
      },
      {
      "shape":"circle",
      "color":"green"
      }
      ]
      }




      Do query:



      db.test.find({"shapes.color": "red"}, {"shapes.color": 1})


      Or



      db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})




      Returns matched document (Document 1), but always with ALL array items in shapes:



      { "shapes": 
      [
      {"shape": "square", "color": "blue"},
      {"shape": "circle", "color": "red"}
      ]
      }


      However, I'd like to get the document (Document 1) only with the array that contains color=red:



      { "shapes": 
      [
      {"shape": "circle", "color": "red"}
      ]
      }


      How can I do this?










      share|improve this question

















      Suppose you have the following documents in my collection:



      {  
      "_id":ObjectId("562e7c594c12942f08fe4192"),
      "shapes":[
      {
      "shape":"square",
      "color":"blue"
      },
      {
      "shape":"circle",
      "color":"red"
      }
      ]
      },
      {
      "_id":ObjectId("562e7c594c12942f08fe4193"),
      "shapes":[
      {
      "shape":"square",
      "color":"black"
      },
      {
      "shape":"circle",
      "color":"green"
      }
      ]
      }




      Do query:



      db.test.find({"shapes.color": "red"}, {"shapes.color": 1})


      Or



      db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})




      Returns matched document (Document 1), but always with ALL array items in shapes:



      { "shapes": 
      [
      {"shape": "square", "color": "blue"},
      {"shape": "circle", "color": "red"}
      ]
      }


      However, I'd like to get the document (Document 1) only with the array that contains color=red:



      { "shapes": 
      [
      {"shape": "circle", "color": "red"}
      ]
      }


      How can I do this?







      mongodb mongodb-query aggregation-framework






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jul 2 '17 at 5:34









      Neil Lunn

      96.4k22169180




      96.4k22169180










      asked Oct 21 '10 at 7:31









      Sebtm

      2,71762430




      2,71762430
























          11 Answers
          11






          active

          oldest

          votes

















          up vote
          334
          down vote



          accepted










          MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





          db.test.find(
          {"shapes.color": "red"},
          {_id: 0, shapes: {$elemMatch: {color: "red"}}});


          Returns:



          {"shapes" : [{"shape": "circle", "color": "red"}]}


          In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



          db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


          MongoDB 3.2 Update



          Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



          db.test.aggregate([
          // Get just the docs that contain a shapes element where color is 'red'
          {$match: {'shapes.color': 'red'}},
          {$project: {
          shapes: {$filter: {
          input: '$shapes',
          as: 'shape',
          cond: {$eq: ['$$shape.color', 'red']}
          }},
          _id: 0
          }}
          ])


          Results:



          [ 
          {
          "shapes" : [
          {
          "shape" : "circle",
          "color" : "red"
          }
          ]
          }
          ]





          share|improve this answer



















          • 57




            Note that as the documentation tells you both $elemMatch and $ only return the first match.
            – kynan
            Feb 3 '13 at 0:26






          • 12




            any solution if I want it to return every elements that matches it instead of just the first?
            – Steve Ng
            Dec 25 '13 at 8:12










          • @JohnnyHK, yup, i used it eventually, thanks!
            – Steve Ng
            Dec 26 '13 at 6:19










          • but this just returns the first matched element!
            – charliebrownie
            Jan 10 '16 at 20:18






          • 1




            @charliebrownie See the option using $filter to get all matches.
            – JohnnyHK
            Jan 10 '16 at 20:29


















          up vote
          93
          down vote













          The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



          db.test.aggregate(
          // Start with a $match pipeline which can take advantage of an index and limit documents processed
          { $match : {
          "shapes.color": "red"
          }},
          { $unwind : "$shapes" },
          { $match : {
          "shapes.color": "red"
          }}
          )


          Results in:



          {
          "result" : [
          {
          "_id" : ObjectId("504425059b7c9fa7ec92beec"),
          "shapes" : {
          "shape" : "circle",
          "color" : "red"
          }
          }
          ],
          "ok" : 1
          }





          share|improve this answer



















          • 6




            @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
            – Stennie
            Sep 3 '12 at 4:24






          • 1




            Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
            – JohnnyHK
            Sep 3 '12 at 4:35








          • 3




            @JohnnyHK: No worries, there are now three useful answers for the question ;-)
            – Stennie
            Sep 3 '12 at 4:41










          • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
            – user1063287
            Dec 4 '14 at 8:23








          • 2




            @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
            – Stennie
            Jan 28 '15 at 8:52


















          up vote
          28
          down vote














          Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




          The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



          The easiest way is to just filter the shapes in the client.



          If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



          function map() {
          filteredShapes = ;

          this.shapes.forEach(function (s) {
          if (s.color === "red") {
          filteredShapes.push(s);
          }
          });

          emit(this._id, { shapes: filteredShapes });
          }

          function reduce(key, values) {
          return values[0];
          }

          res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

          db[res.result].find()





          share|improve this answer






























            up vote
            27
            down vote













            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



            db.test.aggregate([
            { $match: {
            shapes: { $elemMatch: {color: "red"} }
            }},
            { $redact : {
            $cond: {
            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
            then: "$$DESCEND",
            else: "$$PRUNE"
            }
            }}]);


            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.






            share|improve this answer

















            • 1




              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
              – manojpt
              Apr 21 '15 at 11:21










            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
              – manojpt
              Apr 23 '15 at 8:13












            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
              – anvarik
              Apr 23 '15 at 16:36










            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
              – manojpt
              Apr 24 '15 at 4:47






            • 2




              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
              – Onosa
              Dec 30 '15 at 14:46


















            up vote
            16
            down vote













            Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



            db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


            $slice is helpful when you know the index of the element, but sometimes you want
            whichever array element matched your criteria. You can return the matching element
            with the $ operator.






            share|improve this answer






























              up vote
              11
              down vote













              The syntax for find in mongodb is



                  db.<collection name>.find(query, projection);


              and the second query that you have written, that is



                  db.test.find(
              {shapes: {"$elemMatch": {color: "red"}}},
              {"shapes.color":1})


              in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                   db.users.find(
              {"shapes.color":"red"},
              {_id:0, shapes: {$elemMatch : {color: "red"}}})


              This will give you the desired result.






              share|improve this answer



















              • 1




                This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                – Erik Olson
                May 9 '14 at 20:35






              • 2




                @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                – Vicky
                May 11 '14 at 9:22










              • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                – newman
                Aug 29 '15 at 23:05


















              up vote
              11
              down vote













               db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


              OUTPUTS



              {

              "shapes" : [
              {
              "shape" : "circle",
              "color" : "red"
              }
              ]
              }





              share|improve this answer




























                up vote
                7
                down vote













                Thanks to JohnnyHK.



                Here I just want to add some more complex usage.



                // Document 
                {
                "_id" : 1
                "shapes" : [
                {"shape" : "square", "color" : "red"},
                {"shape" : "circle", "color" : "green"}
                ]
                }

                {
                "_id" : 2
                "shapes" : [
                {"shape" : "square", "color" : "red"},
                {"shape" : "circle", "color" : "green"}
                ]
                }


                // The Query
                db.contents.find({
                "_id" : ObjectId(1),
                "shapes.color":"red"
                },{
                "_id": 0,
                "shapes" :{
                "$elemMatch":{
                "color" : "red"
                }
                }
                })


                //And the Result

                {"shapes":[
                {
                "shape" : "square",
                "color" : "red"
                }
                ]}





                share|improve this answer






























                  up vote
                  5
                  down vote













                  You just need to run query



                  db.test.find(
                  {"shapes.color": "red"},
                  {shapes: {$elemMatch: {color: "red"}}});


                  output of this query is



                  {
                  "_id" : ObjectId("562e7c594c12942f08fe4192"),
                  "shapes" : [
                  {"shape" : "circle", "color" : "red"}
                  ]
                  }


                  as you expected it'll gives the exact field from array that matches color:'red'.






                  share|improve this answer






























                    up vote
                    2
                    down vote













                    along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                    db.test.aggregate(
                    { "$unwind" : "$shapes" },
                    { "$match" : {
                    "shapes.color": "red"
                    }},
                    {"$project":{
                    "_id":1,
                    "item":1
                    }}
                    )





                    share|improve this answer





















                    • can you pls describe that this accomplishes with an input and output set?
                      – Alexander Mills
                      Nov 24 '15 at 17:13


















                    up vote
                    0
                    down vote













                    db.test.find( {"shapes.color": "red"}, {_id: 0})





                    share|improve this answer























                    • Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                      – sepehr
                      Oct 25 at 15:06










                    protected by Samuel Liew Oct 5 '15 at 9:21



                    Thank you for your interest in this question.
                    Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                    Would you like to answer one of these unanswered questions instead?














                    11 Answers
                    11






                    active

                    oldest

                    votes








                    11 Answers
                    11






                    active

                    oldest

                    votes









                    active

                    oldest

                    votes






                    active

                    oldest

                    votes








                    up vote
                    334
                    down vote



                    accepted










                    MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





                    db.test.find(
                    {"shapes.color": "red"},
                    {_id: 0, shapes: {$elemMatch: {color: "red"}}});


                    Returns:



                    {"shapes" : [{"shape": "circle", "color": "red"}]}


                    In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



                    db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


                    MongoDB 3.2 Update



                    Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



                    db.test.aggregate([
                    // Get just the docs that contain a shapes element where color is 'red'
                    {$match: {'shapes.color': 'red'}},
                    {$project: {
                    shapes: {$filter: {
                    input: '$shapes',
                    as: 'shape',
                    cond: {$eq: ['$$shape.color', 'red']}
                    }},
                    _id: 0
                    }}
                    ])


                    Results:



                    [ 
                    {
                    "shapes" : [
                    {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    ]
                    }
                    ]





                    share|improve this answer



















                    • 57




                      Note that as the documentation tells you both $elemMatch and $ only return the first match.
                      – kynan
                      Feb 3 '13 at 0:26






                    • 12




                      any solution if I want it to return every elements that matches it instead of just the first?
                      – Steve Ng
                      Dec 25 '13 at 8:12










                    • @JohnnyHK, yup, i used it eventually, thanks!
                      – Steve Ng
                      Dec 26 '13 at 6:19










                    • but this just returns the first matched element!
                      – charliebrownie
                      Jan 10 '16 at 20:18






                    • 1




                      @charliebrownie See the option using $filter to get all matches.
                      – JohnnyHK
                      Jan 10 '16 at 20:29















                    up vote
                    334
                    down vote



                    accepted










                    MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





                    db.test.find(
                    {"shapes.color": "red"},
                    {_id: 0, shapes: {$elemMatch: {color: "red"}}});


                    Returns:



                    {"shapes" : [{"shape": "circle", "color": "red"}]}


                    In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



                    db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


                    MongoDB 3.2 Update



                    Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



                    db.test.aggregate([
                    // Get just the docs that contain a shapes element where color is 'red'
                    {$match: {'shapes.color': 'red'}},
                    {$project: {
                    shapes: {$filter: {
                    input: '$shapes',
                    as: 'shape',
                    cond: {$eq: ['$$shape.color', 'red']}
                    }},
                    _id: 0
                    }}
                    ])


                    Results:



                    [ 
                    {
                    "shapes" : [
                    {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    ]
                    }
                    ]





                    share|improve this answer



















                    • 57




                      Note that as the documentation tells you both $elemMatch and $ only return the first match.
                      – kynan
                      Feb 3 '13 at 0:26






                    • 12




                      any solution if I want it to return every elements that matches it instead of just the first?
                      – Steve Ng
                      Dec 25 '13 at 8:12










                    • @JohnnyHK, yup, i used it eventually, thanks!
                      – Steve Ng
                      Dec 26 '13 at 6:19










                    • but this just returns the first matched element!
                      – charliebrownie
                      Jan 10 '16 at 20:18






                    • 1




                      @charliebrownie See the option using $filter to get all matches.
                      – JohnnyHK
                      Jan 10 '16 at 20:29













                    up vote
                    334
                    down vote



                    accepted







                    up vote
                    334
                    down vote



                    accepted






                    MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





                    db.test.find(
                    {"shapes.color": "red"},
                    {_id: 0, shapes: {$elemMatch: {color: "red"}}});


                    Returns:



                    {"shapes" : [{"shape": "circle", "color": "red"}]}


                    In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



                    db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


                    MongoDB 3.2 Update



                    Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



                    db.test.aggregate([
                    // Get just the docs that contain a shapes element where color is 'red'
                    {$match: {'shapes.color': 'red'}},
                    {$project: {
                    shapes: {$filter: {
                    input: '$shapes',
                    as: 'shape',
                    cond: {$eq: ['$$shape.color', 'red']}
                    }},
                    _id: 0
                    }}
                    ])


                    Results:



                    [ 
                    {
                    "shapes" : [
                    {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    ]
                    }
                    ]





                    share|improve this answer














                    MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





                    db.test.find(
                    {"shapes.color": "red"},
                    {_id: 0, shapes: {$elemMatch: {color: "red"}}});


                    Returns:



                    {"shapes" : [{"shape": "circle", "color": "red"}]}


                    In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



                    db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


                    MongoDB 3.2 Update



                    Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



                    db.test.aggregate([
                    // Get just the docs that contain a shapes element where color is 'red'
                    {$match: {'shapes.color': 'red'}},
                    {$project: {
                    shapes: {$filter: {
                    input: '$shapes',
                    as: 'shape',
                    cond: {$eq: ['$$shape.color', 'red']}
                    }},
                    _id: 0
                    }}
                    ])


                    Results:



                    [ 
                    {
                    "shapes" : [
                    {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    ]
                    }
                    ]






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Sep 25 at 18:04









                    Faraz Durrani

                    2,6542934




                    2,6542934










                    answered Sep 3 '12 at 4:19









                    JohnnyHK

                    204k37431362




                    204k37431362








                    • 57




                      Note that as the documentation tells you both $elemMatch and $ only return the first match.
                      – kynan
                      Feb 3 '13 at 0:26






                    • 12




                      any solution if I want it to return every elements that matches it instead of just the first?
                      – Steve Ng
                      Dec 25 '13 at 8:12










                    • @JohnnyHK, yup, i used it eventually, thanks!
                      – Steve Ng
                      Dec 26 '13 at 6:19










                    • but this just returns the first matched element!
                      – charliebrownie
                      Jan 10 '16 at 20:18






                    • 1




                      @charliebrownie See the option using $filter to get all matches.
                      – JohnnyHK
                      Jan 10 '16 at 20:29














                    • 57




                      Note that as the documentation tells you both $elemMatch and $ only return the first match.
                      – kynan
                      Feb 3 '13 at 0:26






                    • 12




                      any solution if I want it to return every elements that matches it instead of just the first?
                      – Steve Ng
                      Dec 25 '13 at 8:12










                    • @JohnnyHK, yup, i used it eventually, thanks!
                      – Steve Ng
                      Dec 26 '13 at 6:19










                    • but this just returns the first matched element!
                      – charliebrownie
                      Jan 10 '16 at 20:18






                    • 1




                      @charliebrownie See the option using $filter to get all matches.
                      – JohnnyHK
                      Jan 10 '16 at 20:29








                    57




                    57




                    Note that as the documentation tells you both $elemMatch and $ only return the first match.
                    – kynan
                    Feb 3 '13 at 0:26




                    Note that as the documentation tells you both $elemMatch and $ only return the first match.
                    – kynan
                    Feb 3 '13 at 0:26




                    12




                    12




                    any solution if I want it to return every elements that matches it instead of just the first?
                    – Steve Ng
                    Dec 25 '13 at 8:12




                    any solution if I want it to return every elements that matches it instead of just the first?
                    – Steve Ng
                    Dec 25 '13 at 8:12












                    @JohnnyHK, yup, i used it eventually, thanks!
                    – Steve Ng
                    Dec 26 '13 at 6:19




                    @JohnnyHK, yup, i used it eventually, thanks!
                    – Steve Ng
                    Dec 26 '13 at 6:19












                    but this just returns the first matched element!
                    – charliebrownie
                    Jan 10 '16 at 20:18




                    but this just returns the first matched element!
                    – charliebrownie
                    Jan 10 '16 at 20:18




                    1




                    1




                    @charliebrownie See the option using $filter to get all matches.
                    – JohnnyHK
                    Jan 10 '16 at 20:29




                    @charliebrownie See the option using $filter to get all matches.
                    – JohnnyHK
                    Jan 10 '16 at 20:29












                    up vote
                    93
                    down vote













                    The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



                    db.test.aggregate(
                    // Start with a $match pipeline which can take advantage of an index and limit documents processed
                    { $match : {
                    "shapes.color": "red"
                    }},
                    { $unwind : "$shapes" },
                    { $match : {
                    "shapes.color": "red"
                    }}
                    )


                    Results in:



                    {
                    "result" : [
                    {
                    "_id" : ObjectId("504425059b7c9fa7ec92beec"),
                    "shapes" : {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    }
                    ],
                    "ok" : 1
                    }





                    share|improve this answer



















                    • 6




                      @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                      – Stennie
                      Sep 3 '12 at 4:24






                    • 1




                      Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                      – JohnnyHK
                      Sep 3 '12 at 4:35








                    • 3




                      @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                      – Stennie
                      Sep 3 '12 at 4:41










                    • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                      – user1063287
                      Dec 4 '14 at 8:23








                    • 2




                      @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                      – Stennie
                      Jan 28 '15 at 8:52















                    up vote
                    93
                    down vote













                    The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



                    db.test.aggregate(
                    // Start with a $match pipeline which can take advantage of an index and limit documents processed
                    { $match : {
                    "shapes.color": "red"
                    }},
                    { $unwind : "$shapes" },
                    { $match : {
                    "shapes.color": "red"
                    }}
                    )


                    Results in:



                    {
                    "result" : [
                    {
                    "_id" : ObjectId("504425059b7c9fa7ec92beec"),
                    "shapes" : {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    }
                    ],
                    "ok" : 1
                    }





                    share|improve this answer



















                    • 6




                      @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                      – Stennie
                      Sep 3 '12 at 4:24






                    • 1




                      Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                      – JohnnyHK
                      Sep 3 '12 at 4:35








                    • 3




                      @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                      – Stennie
                      Sep 3 '12 at 4:41










                    • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                      – user1063287
                      Dec 4 '14 at 8:23








                    • 2




                      @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                      – Stennie
                      Jan 28 '15 at 8:52













                    up vote
                    93
                    down vote










                    up vote
                    93
                    down vote









                    The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



                    db.test.aggregate(
                    // Start with a $match pipeline which can take advantage of an index and limit documents processed
                    { $match : {
                    "shapes.color": "red"
                    }},
                    { $unwind : "$shapes" },
                    { $match : {
                    "shapes.color": "red"
                    }}
                    )


                    Results in:



                    {
                    "result" : [
                    {
                    "_id" : ObjectId("504425059b7c9fa7ec92beec"),
                    "shapes" : {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    }
                    ],
                    "ok" : 1
                    }





                    share|improve this answer














                    The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



                    db.test.aggregate(
                    // Start with a $match pipeline which can take advantage of an index and limit documents processed
                    { $match : {
                    "shapes.color": "red"
                    }},
                    { $unwind : "$shapes" },
                    { $match : {
                    "shapes.color": "red"
                    }}
                    )


                    Results in:



                    {
                    "result" : [
                    {
                    "_id" : ObjectId("504425059b7c9fa7ec92beec"),
                    "shapes" : {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    }
                    ],
                    "ok" : 1
                    }






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Jan 28 '15 at 8:41

























                    answered Sep 3 '12 at 3:44









                    Stennie

                    45.8k8108138




                    45.8k8108138








                    • 6




                      @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                      – Stennie
                      Sep 3 '12 at 4:24






                    • 1




                      Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                      – JohnnyHK
                      Sep 3 '12 at 4:35








                    • 3




                      @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                      – Stennie
                      Sep 3 '12 at 4:41










                    • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                      – user1063287
                      Dec 4 '14 at 8:23








                    • 2




                      @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                      – Stennie
                      Jan 28 '15 at 8:52














                    • 6




                      @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                      – Stennie
                      Sep 3 '12 at 4:24






                    • 1




                      Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                      – JohnnyHK
                      Sep 3 '12 at 4:35








                    • 3




                      @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                      – Stennie
                      Sep 3 '12 at 4:41










                    • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                      – user1063287
                      Dec 4 '14 at 8:23








                    • 2




                      @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                      – Stennie
                      Jan 28 '15 at 8:52








                    6




                    6




                    @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                    – Stennie
                    Sep 3 '12 at 4:24




                    @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                    – Stennie
                    Sep 3 '12 at 4:24




                    1




                    1




                    Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                    – JohnnyHK
                    Sep 3 '12 at 4:35






                    Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                    – JohnnyHK
                    Sep 3 '12 at 4:35






                    3




                    3




                    @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                    – Stennie
                    Sep 3 '12 at 4:41




                    @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                    – Stennie
                    Sep 3 '12 at 4:41












                    For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                    – user1063287
                    Dec 4 '14 at 8:23






                    For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                    – user1063287
                    Dec 4 '14 at 8:23






                    2




                    2




                    @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                    – Stennie
                    Jan 28 '15 at 8:52




                    @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                    – Stennie
                    Jan 28 '15 at 8:52










                    up vote
                    28
                    down vote














                    Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




                    The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



                    The easiest way is to just filter the shapes in the client.



                    If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



                    function map() {
                    filteredShapes = ;

                    this.shapes.forEach(function (s) {
                    if (s.color === "red") {
                    filteredShapes.push(s);
                    }
                    });

                    emit(this._id, { shapes: filteredShapes });
                    }

                    function reduce(key, values) {
                    return values[0];
                    }

                    res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

                    db[res.result].find()





                    share|improve this answer



























                      up vote
                      28
                      down vote














                      Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




                      The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



                      The easiest way is to just filter the shapes in the client.



                      If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



                      function map() {
                      filteredShapes = ;

                      this.shapes.forEach(function (s) {
                      if (s.color === "red") {
                      filteredShapes.push(s);
                      }
                      });

                      emit(this._id, { shapes: filteredShapes });
                      }

                      function reduce(key, values) {
                      return values[0];
                      }

                      res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

                      db[res.result].find()





                      share|improve this answer

























                        up vote
                        28
                        down vote










                        up vote
                        28
                        down vote










                        Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




                        The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



                        The easiest way is to just filter the shapes in the client.



                        If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



                        function map() {
                        filteredShapes = ;

                        this.shapes.forEach(function (s) {
                        if (s.color === "red") {
                        filteredShapes.push(s);
                        }
                        });

                        emit(this._id, { shapes: filteredShapes });
                        }

                        function reduce(key, values) {
                        return values[0];
                        }

                        res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

                        db[res.result].find()





                        share|improve this answer















                        Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




                        The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



                        The easiest way is to just filter the shapes in the client.



                        If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



                        function map() {
                        filteredShapes = ;

                        this.shapes.forEach(function (s) {
                        if (s.color === "red") {
                        filteredShapes.push(s);
                        }
                        });

                        emit(this._id, { shapes: filteredShapes });
                        }

                        function reduce(key, values) {
                        return values[0];
                        }

                        res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

                        db[res.result].find()






                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Jul 19 '16 at 18:42

























                        answered Oct 21 '10 at 9:25









                        Niels van der Rest

                        22.8k137182




                        22.8k137182






















                            up vote
                            27
                            down vote













                            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



                            db.test.aggregate([
                            { $match: {
                            shapes: { $elemMatch: {color: "red"} }
                            }},
                            { $redact : {
                            $cond: {
                            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
                            then: "$$DESCEND",
                            else: "$$PRUNE"
                            }
                            }}]);


                            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



                            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



                            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.






                            share|improve this answer

















                            • 1




                              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                              – manojpt
                              Apr 21 '15 at 11:21










                            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                              – manojpt
                              Apr 23 '15 at 8:13












                            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                              – anvarik
                              Apr 23 '15 at 16:36










                            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                              – manojpt
                              Apr 24 '15 at 4:47






                            • 2




                              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                              – Onosa
                              Dec 30 '15 at 14:46















                            up vote
                            27
                            down vote













                            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



                            db.test.aggregate([
                            { $match: {
                            shapes: { $elemMatch: {color: "red"} }
                            }},
                            { $redact : {
                            $cond: {
                            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
                            then: "$$DESCEND",
                            else: "$$PRUNE"
                            }
                            }}]);


                            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



                            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



                            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.






                            share|improve this answer

















                            • 1




                              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                              – manojpt
                              Apr 21 '15 at 11:21










                            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                              – manojpt
                              Apr 23 '15 at 8:13












                            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                              – anvarik
                              Apr 23 '15 at 16:36










                            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                              – manojpt
                              Apr 24 '15 at 4:47






                            • 2




                              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                              – Onosa
                              Dec 30 '15 at 14:46













                            up vote
                            27
                            down vote










                            up vote
                            27
                            down vote









                            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



                            db.test.aggregate([
                            { $match: {
                            shapes: { $elemMatch: {color: "red"} }
                            }},
                            { $redact : {
                            $cond: {
                            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
                            then: "$$DESCEND",
                            else: "$$PRUNE"
                            }
                            }}]);


                            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



                            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



                            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.






                            share|improve this answer












                            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



                            db.test.aggregate([
                            { $match: {
                            shapes: { $elemMatch: {color: "red"} }
                            }},
                            { $redact : {
                            $cond: {
                            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
                            then: "$$DESCEND",
                            else: "$$PRUNE"
                            }
                            }}]);


                            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



                            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



                            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jun 4 '14 at 8:31









                            anvarik

                            3,68532947




                            3,68532947








                            • 1




                              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                              – manojpt
                              Apr 21 '15 at 11:21










                            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                              – manojpt
                              Apr 23 '15 at 8:13












                            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                              – anvarik
                              Apr 23 '15 at 16:36










                            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                              – manojpt
                              Apr 24 '15 at 4:47






                            • 2




                              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                              – Onosa
                              Dec 30 '15 at 14:46














                            • 1




                              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                              – manojpt
                              Apr 21 '15 at 11:21










                            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                              – manojpt
                              Apr 23 '15 at 8:13












                            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                              – anvarik
                              Apr 23 '15 at 16:36










                            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                              – manojpt
                              Apr 24 '15 at 4:47






                            • 2




                              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                              – Onosa
                              Dec 30 '15 at 14:46








                            1




                            1




                            perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                            – manojpt
                            Apr 21 '15 at 11:21




                            perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                            – manojpt
                            Apr 21 '15 at 11:21












                            I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                            – manojpt
                            Apr 23 '15 at 8:13






                            I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                            – manojpt
                            Apr 23 '15 at 8:13














                            not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                            – anvarik
                            Apr 23 '15 at 16:36




                            not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                            – anvarik
                            Apr 23 '15 at 16:36












                            okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                            – manojpt
                            Apr 24 '15 at 4:47




                            okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                            – manojpt
                            Apr 24 '15 at 4:47




                            2




                            2




                            Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                            – Onosa
                            Dec 30 '15 at 14:46




                            Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                            – Onosa
                            Dec 30 '15 at 14:46










                            up vote
                            16
                            down vote













                            Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



                            db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


                            $slice is helpful when you know the index of the element, but sometimes you want
                            whichever array element matched your criteria. You can return the matching element
                            with the $ operator.






                            share|improve this answer



























                              up vote
                              16
                              down vote













                              Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



                              db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


                              $slice is helpful when you know the index of the element, but sometimes you want
                              whichever array element matched your criteria. You can return the matching element
                              with the $ operator.






                              share|improve this answer

























                                up vote
                                16
                                down vote










                                up vote
                                16
                                down vote









                                Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



                                db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


                                $slice is helpful when you know the index of the element, but sometimes you want
                                whichever array element matched your criteria. You can return the matching element
                                with the $ operator.






                                share|improve this answer














                                Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



                                db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


                                $slice is helpful when you know the index of the element, but sometimes you want
                                whichever array element matched your criteria. You can return the matching element
                                with the $ operator.







                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Sep 18 '14 at 9:14









                                Egor Neliuba

                                10.2k54163




                                10.2k54163










                                answered Sep 18 '14 at 8:35









                                Naren Dran

                                40246




                                40246






















                                    up vote
                                    11
                                    down vote













                                    The syntax for find in mongodb is



                                        db.<collection name>.find(query, projection);


                                    and the second query that you have written, that is



                                        db.test.find(
                                    {shapes: {"$elemMatch": {color: "red"}}},
                                    {"shapes.color":1})


                                    in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                                         db.users.find(
                                    {"shapes.color":"red"},
                                    {_id:0, shapes: {$elemMatch : {color: "red"}}})


                                    This will give you the desired result.






                                    share|improve this answer



















                                    • 1




                                      This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                      – Erik Olson
                                      May 9 '14 at 20:35






                                    • 2




                                      @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                      – Vicky
                                      May 11 '14 at 9:22










                                    • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                      – newman
                                      Aug 29 '15 at 23:05















                                    up vote
                                    11
                                    down vote













                                    The syntax for find in mongodb is



                                        db.<collection name>.find(query, projection);


                                    and the second query that you have written, that is



                                        db.test.find(
                                    {shapes: {"$elemMatch": {color: "red"}}},
                                    {"shapes.color":1})


                                    in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                                         db.users.find(
                                    {"shapes.color":"red"},
                                    {_id:0, shapes: {$elemMatch : {color: "red"}}})


                                    This will give you the desired result.






                                    share|improve this answer



















                                    • 1




                                      This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                      – Erik Olson
                                      May 9 '14 at 20:35






                                    • 2




                                      @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                      – Vicky
                                      May 11 '14 at 9:22










                                    • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                      – newman
                                      Aug 29 '15 at 23:05













                                    up vote
                                    11
                                    down vote










                                    up vote
                                    11
                                    down vote









                                    The syntax for find in mongodb is



                                        db.<collection name>.find(query, projection);


                                    and the second query that you have written, that is



                                        db.test.find(
                                    {shapes: {"$elemMatch": {color: "red"}}},
                                    {"shapes.color":1})


                                    in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                                         db.users.find(
                                    {"shapes.color":"red"},
                                    {_id:0, shapes: {$elemMatch : {color: "red"}}})


                                    This will give you the desired result.






                                    share|improve this answer














                                    The syntax for find in mongodb is



                                        db.<collection name>.find(query, projection);


                                    and the second query that you have written, that is



                                        db.test.find(
                                    {shapes: {"$elemMatch": {color: "red"}}},
                                    {"shapes.color":1})


                                    in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                                         db.users.find(
                                    {"shapes.color":"red"},
                                    {_id:0, shapes: {$elemMatch : {color: "red"}}})


                                    This will give you the desired result.







                                    share|improve this answer














                                    share|improve this answer



                                    share|improve this answer








                                    edited Jan 31 '14 at 8:19









                                    Jinxcat

                                    4191316




                                    4191316










                                    answered Dec 22 '13 at 8:14









                                    Vicky

                                    447314




                                    447314








                                    • 1




                                      This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                      – Erik Olson
                                      May 9 '14 at 20:35






                                    • 2




                                      @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                      – Vicky
                                      May 11 '14 at 9:22










                                    • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                      – newman
                                      Aug 29 '15 at 23:05














                                    • 1




                                      This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                      – Erik Olson
                                      May 9 '14 at 20:35






                                    • 2




                                      @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                      – Vicky
                                      May 11 '14 at 9:22










                                    • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                      – newman
                                      Aug 29 '15 at 23:05








                                    1




                                    1




                                    This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                    – Erik Olson
                                    May 9 '14 at 20:35




                                    This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                    – Erik Olson
                                    May 9 '14 at 20:35




                                    2




                                    2




                                    @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                    – Vicky
                                    May 11 '14 at 9:22




                                    @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                    – Vicky
                                    May 11 '14 at 9:22












                                    This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                    – newman
                                    Aug 29 '15 at 23:05




                                    This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                    – newman
                                    Aug 29 '15 at 23:05










                                    up vote
                                    11
                                    down vote













                                     db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


                                    OUTPUTS



                                    {

                                    "shapes" : [
                                    {
                                    "shape" : "circle",
                                    "color" : "red"
                                    }
                                    ]
                                    }





                                    share|improve this answer

























                                      up vote
                                      11
                                      down vote













                                       db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


                                      OUTPUTS



                                      {

                                      "shapes" : [
                                      {
                                      "shape" : "circle",
                                      "color" : "red"
                                      }
                                      ]
                                      }





                                      share|improve this answer























                                        up vote
                                        11
                                        down vote










                                        up vote
                                        11
                                        down vote









                                         db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


                                        OUTPUTS



                                        {

                                        "shapes" : [
                                        {
                                        "shape" : "circle",
                                        "color" : "red"
                                        }
                                        ]
                                        }





                                        share|improve this answer












                                         db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


                                        OUTPUTS



                                        {

                                        "shapes" : [
                                        {
                                        "shape" : "circle",
                                        "color" : "red"
                                        }
                                        ]
                                        }






                                        share|improve this answer












                                        share|improve this answer



                                        share|improve this answer










                                        answered Dec 7 '16 at 6:25









                                        Viral Patel

                                        54369




                                        54369






















                                            up vote
                                            7
                                            down vote













                                            Thanks to JohnnyHK.



                                            Here I just want to add some more complex usage.



                                            // Document 
                                            {
                                            "_id" : 1
                                            "shapes" : [
                                            {"shape" : "square", "color" : "red"},
                                            {"shape" : "circle", "color" : "green"}
                                            ]
                                            }

                                            {
                                            "_id" : 2
                                            "shapes" : [
                                            {"shape" : "square", "color" : "red"},
                                            {"shape" : "circle", "color" : "green"}
                                            ]
                                            }


                                            // The Query
                                            db.contents.find({
                                            "_id" : ObjectId(1),
                                            "shapes.color":"red"
                                            },{
                                            "_id": 0,
                                            "shapes" :{
                                            "$elemMatch":{
                                            "color" : "red"
                                            }
                                            }
                                            })


                                            //And the Result

                                            {"shapes":[
                                            {
                                            "shape" : "square",
                                            "color" : "red"
                                            }
                                            ]}





                                            share|improve this answer



























                                              up vote
                                              7
                                              down vote













                                              Thanks to JohnnyHK.



                                              Here I just want to add some more complex usage.



                                              // Document 
                                              {
                                              "_id" : 1
                                              "shapes" : [
                                              {"shape" : "square", "color" : "red"},
                                              {"shape" : "circle", "color" : "green"}
                                              ]
                                              }

                                              {
                                              "_id" : 2
                                              "shapes" : [
                                              {"shape" : "square", "color" : "red"},
                                              {"shape" : "circle", "color" : "green"}
                                              ]
                                              }


                                              // The Query
                                              db.contents.find({
                                              "_id" : ObjectId(1),
                                              "shapes.color":"red"
                                              },{
                                              "_id": 0,
                                              "shapes" :{
                                              "$elemMatch":{
                                              "color" : "red"
                                              }
                                              }
                                              })


                                              //And the Result

                                              {"shapes":[
                                              {
                                              "shape" : "square",
                                              "color" : "red"
                                              }
                                              ]}





                                              share|improve this answer

























                                                up vote
                                                7
                                                down vote










                                                up vote
                                                7
                                                down vote









                                                Thanks to JohnnyHK.



                                                Here I just want to add some more complex usage.



                                                // Document 
                                                {
                                                "_id" : 1
                                                "shapes" : [
                                                {"shape" : "square", "color" : "red"},
                                                {"shape" : "circle", "color" : "green"}
                                                ]
                                                }

                                                {
                                                "_id" : 2
                                                "shapes" : [
                                                {"shape" : "square", "color" : "red"},
                                                {"shape" : "circle", "color" : "green"}
                                                ]
                                                }


                                                // The Query
                                                db.contents.find({
                                                "_id" : ObjectId(1),
                                                "shapes.color":"red"
                                                },{
                                                "_id": 0,
                                                "shapes" :{
                                                "$elemMatch":{
                                                "color" : "red"
                                                }
                                                }
                                                })


                                                //And the Result

                                                {"shapes":[
                                                {
                                                "shape" : "square",
                                                "color" : "red"
                                                }
                                                ]}





                                                share|improve this answer














                                                Thanks to JohnnyHK.



                                                Here I just want to add some more complex usage.



                                                // Document 
                                                {
                                                "_id" : 1
                                                "shapes" : [
                                                {"shape" : "square", "color" : "red"},
                                                {"shape" : "circle", "color" : "green"}
                                                ]
                                                }

                                                {
                                                "_id" : 2
                                                "shapes" : [
                                                {"shape" : "square", "color" : "red"},
                                                {"shape" : "circle", "color" : "green"}
                                                ]
                                                }


                                                // The Query
                                                db.contents.find({
                                                "_id" : ObjectId(1),
                                                "shapes.color":"red"
                                                },{
                                                "_id": 0,
                                                "shapes" :{
                                                "$elemMatch":{
                                                "color" : "red"
                                                }
                                                }
                                                })


                                                //And the Result

                                                {"shapes":[
                                                {
                                                "shape" : "square",
                                                "color" : "red"
                                                }
                                                ]}






                                                share|improve this answer














                                                share|improve this answer



                                                share|improve this answer








                                                edited May 23 '17 at 11:54









                                                Community

                                                11




                                                11










                                                answered Mar 23 '14 at 7:05









                                                Eddy

                                                1,8272427




                                                1,8272427






















                                                    up vote
                                                    5
                                                    down vote













                                                    You just need to run query



                                                    db.test.find(
                                                    {"shapes.color": "red"},
                                                    {shapes: {$elemMatch: {color: "red"}}});


                                                    output of this query is



                                                    {
                                                    "_id" : ObjectId("562e7c594c12942f08fe4192"),
                                                    "shapes" : [
                                                    {"shape" : "circle", "color" : "red"}
                                                    ]
                                                    }


                                                    as you expected it'll gives the exact field from array that matches color:'red'.






                                                    share|improve this answer



























                                                      up vote
                                                      5
                                                      down vote













                                                      You just need to run query



                                                      db.test.find(
                                                      {"shapes.color": "red"},
                                                      {shapes: {$elemMatch: {color: "red"}}});


                                                      output of this query is



                                                      {
                                                      "_id" : ObjectId("562e7c594c12942f08fe4192"),
                                                      "shapes" : [
                                                      {"shape" : "circle", "color" : "red"}
                                                      ]
                                                      }


                                                      as you expected it'll gives the exact field from array that matches color:'red'.






                                                      share|improve this answer

























                                                        up vote
                                                        5
                                                        down vote










                                                        up vote
                                                        5
                                                        down vote









                                                        You just need to run query



                                                        db.test.find(
                                                        {"shapes.color": "red"},
                                                        {shapes: {$elemMatch: {color: "red"}}});


                                                        output of this query is



                                                        {
                                                        "_id" : ObjectId("562e7c594c12942f08fe4192"),
                                                        "shapes" : [
                                                        {"shape" : "circle", "color" : "red"}
                                                        ]
                                                        }


                                                        as you expected it'll gives the exact field from array that matches color:'red'.






                                                        share|improve this answer














                                                        You just need to run query



                                                        db.test.find(
                                                        {"shapes.color": "red"},
                                                        {shapes: {$elemMatch: {color: "red"}}});


                                                        output of this query is



                                                        {
                                                        "_id" : ObjectId("562e7c594c12942f08fe4192"),
                                                        "shapes" : [
                                                        {"shape" : "circle", "color" : "red"}
                                                        ]
                                                        }


                                                        as you expected it'll gives the exact field from array that matches color:'red'.







                                                        share|improve this answer














                                                        share|improve this answer



                                                        share|improve this answer








                                                        edited Nov 10 '16 at 7:50









                                                        azhar

                                                        8341932




                                                        8341932










                                                        answered Sep 17 '16 at 17:22









                                                        Vaibhav Patil

                                                        542514




                                                        542514






















                                                            up vote
                                                            2
                                                            down vote













                                                            along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                                                            db.test.aggregate(
                                                            { "$unwind" : "$shapes" },
                                                            { "$match" : {
                                                            "shapes.color": "red"
                                                            }},
                                                            {"$project":{
                                                            "_id":1,
                                                            "item":1
                                                            }}
                                                            )





                                                            share|improve this answer





















                                                            • can you pls describe that this accomplishes with an input and output set?
                                                              – Alexander Mills
                                                              Nov 24 '15 at 17:13















                                                            up vote
                                                            2
                                                            down vote













                                                            along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                                                            db.test.aggregate(
                                                            { "$unwind" : "$shapes" },
                                                            { "$match" : {
                                                            "shapes.color": "red"
                                                            }},
                                                            {"$project":{
                                                            "_id":1,
                                                            "item":1
                                                            }}
                                                            )





                                                            share|improve this answer





















                                                            • can you pls describe that this accomplishes with an input and output set?
                                                              – Alexander Mills
                                                              Nov 24 '15 at 17:13













                                                            up vote
                                                            2
                                                            down vote










                                                            up vote
                                                            2
                                                            down vote









                                                            along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                                                            db.test.aggregate(
                                                            { "$unwind" : "$shapes" },
                                                            { "$match" : {
                                                            "shapes.color": "red"
                                                            }},
                                                            {"$project":{
                                                            "_id":1,
                                                            "item":1
                                                            }}
                                                            )





                                                            share|improve this answer












                                                            along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                                                            db.test.aggregate(
                                                            { "$unwind" : "$shapes" },
                                                            { "$match" : {
                                                            "shapes.color": "red"
                                                            }},
                                                            {"$project":{
                                                            "_id":1,
                                                            "item":1
                                                            }}
                                                            )






                                                            share|improve this answer












                                                            share|improve this answer



                                                            share|improve this answer










                                                            answered Feb 9 '13 at 15:45









                                                            shakthydoss

                                                            1,32521530




                                                            1,32521530












                                                            • can you pls describe that this accomplishes with an input and output set?
                                                              – Alexander Mills
                                                              Nov 24 '15 at 17:13


















                                                            • can you pls describe that this accomplishes with an input and output set?
                                                              – Alexander Mills
                                                              Nov 24 '15 at 17:13
















                                                            can you pls describe that this accomplishes with an input and output set?
                                                            – Alexander Mills
                                                            Nov 24 '15 at 17:13




                                                            can you pls describe that this accomplishes with an input and output set?
                                                            – Alexander Mills
                                                            Nov 24 '15 at 17:13










                                                            up vote
                                                            0
                                                            down vote













                                                            db.test.find( {"shapes.color": "red"}, {_id: 0})





                                                            share|improve this answer























                                                            • Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                              – sepehr
                                                              Oct 25 at 15:06















                                                            up vote
                                                            0
                                                            down vote













                                                            db.test.find( {"shapes.color": "red"}, {_id: 0})





                                                            share|improve this answer























                                                            • Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                              – sepehr
                                                              Oct 25 at 15:06













                                                            up vote
                                                            0
                                                            down vote










                                                            up vote
                                                            0
                                                            down vote









                                                            db.test.find( {"shapes.color": "red"}, {_id: 0})





                                                            share|improve this answer














                                                            db.test.find( {"shapes.color": "red"}, {_id: 0})






                                                            share|improve this answer














                                                            share|improve this answer



                                                            share|improve this answer








                                                            edited Oct 25 at 8:04









                                                            Suraj Rao

                                                            22.4k75469




                                                            22.4k75469










                                                            answered Oct 25 at 8:00









                                                            Poonam Agrawal

                                                            92




                                                            92












                                                            • Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                              – sepehr
                                                              Oct 25 at 15:06


















                                                            • Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                              – sepehr
                                                              Oct 25 at 15:06
















                                                            Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                            – sepehr
                                                            Oct 25 at 15:06




                                                            Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                            – sepehr
                                                            Oct 25 at 15:06





                                                            protected by Samuel Liew Oct 5 '15 at 9:21



                                                            Thank you for your interest in this question.
                                                            Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                                                            Would you like to answer one of these unanswered questions instead?



                                                            Popular posts from this blog

                                                            Bressuire

                                                            Vorschmack

                                                            Quarantine