views:

24

answers:

1

Suppose you have the following:

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


// Document 2
{ "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})

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

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

I just want document (Document 1) filtered with ONLY array item color=red:

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

How ?

+1  A: 

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()
Niels van der Rest