varios tutorial registro modificar lista insertar español documentos documento consultas comandos avanzadas mongodb mongodb-query aggregation-framework

tutorial - mongodb modificar documento



Recuperar solo el elemento consultado en una matriz de objetos en la colección MongoDB (11)

Supongamos que tiene los siguientes documentos en mi colección:

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

Hacer consulta:

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

O

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

Devuelve el documento coincidente (Documento 1) , pero siempre con TODOS los elementos de matriz en shapes :

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

Sin embargo, me gustaría obtener el documento (Documento 1) solo con la matriz que contiene color=red :

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

¿Cómo puedo hacer esto?


Precaución: esta respuesta proporciona una solución que era relevante en ese momento , antes de que se introdujeran las nuevas características de MongoDB 2.2 y posteriores. Vea las otras respuestas si está utilizando una versión más reciente de MongoDB.

El parámetro selector de campo está limitado a propiedades completas. No se puede utilizar para seleccionar parte de una matriz, solo la matriz completa. Intenté usar el operador $ posicional , pero eso no funcionó.

La forma más fácil es simplemente filtrar las formas en el cliente .

Si realmente necesita la salida correcta directamente de MongoDB, puede usar un mapa reducido para filtrar las formas.

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()


Gracias a .

Aquí solo quiero añadir un uso más complejo.

// 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" } ]}


El nuevo marco de agregación en MongoDB 2.2+ proporciona una alternativa a Map / Reduce. El operador $unwind se puede usar para separar la matriz de shapes en una secuencia de documentos que pueden combinarse:

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" }} )

Resultados en:

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


El nuevo operador de proyección $elemMatch MongoDB 2.2 proporciona otra forma de modificar el documento devuelto para que contenga solo el primer elemento de shapes coincidentes:

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

Devoluciones:

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

En 2.2 también puede hacer esto usando el $ projection operator , donde $ en el nombre de un campo de objeto de proyección representa el índice del primer elemento de matriz coincidente del campo de la consulta. Lo siguiente devuelve los mismos resultados que arriba:

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

Actualización de MongoDB 3.2

A partir de la versión 3.2, puede usar el nuevo operador de agregación de $filter para filtrar una matriz durante la proyección, que tiene la ventaja de incluir todas las coincidencias, en lugar de solo la primera.

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 }} ])

Resultados:

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


La sintaxis para encontrar en mongodb es

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

y la segunda consulta que has escrito, que es

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

en esto, ha utilizado el operador $elemMatch en la parte de consulta, mientras que si usa este operador en la parte de proyección, obtendrá el resultado deseado. Puede escribir su consulta como

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

Esto le dará el resultado deseado.


Mejor puede consultar en el elemento de matriz correspondiente usando $slice Es útil devolver el objeto significativo en una matriz.

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

$slice es útil cuando conoce el índice del elemento, pero a veces desea que cualquier elemento de matriz coincida con sus criterios. Puede devolver el elemento correspondiente con el operador $ .


Otra forma $redact es usar $redact , que es una de las nuevas características de agregación de MongoDB 2.6 . Si está utilizando 2.6, no necesita un $ rebobinado que podría causarle problemas de rendimiento si tiene matrices grandes.

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

$redact "restringe el contenido de los documentos en función de la información almacenada en los propios documentos" . Por lo que se ejecutará sólo dentro del documento . Básicamente, escanea su documento de arriba abajo y comprueba si coincide con su condición if que está en $cond , si hay coincidencia mantendrá el contenido ( $$DESCEND ) o eliminará ( $$PRUNE ).

En el ejemplo anterior, la primera $match devuelve la matriz de shapes completa, y $ redact la elimina hasta el resultado esperado.

Tenga en cuenta que {$not:"$color"} es necesario, ya que también escaneará el documento superior, y si $redact no encuentra un campo de color en el nivel superior, esto devolverá el valor false que podría eliminar todo el documento que no quiero


Solo necesitas ejecutar la consulta

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

la salida de esta consulta es

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

como esperaba, le dará el campo exacto de la matriz que coincide con el color: ''rojo''.


junto con $ project será más apropiado, ya que otros elementos coincidentes sabios serán apiñados junto con otros elementos en el documento.

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


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

SALIDAS

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


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