¿Puede mongo añadir datos de matriz?

Tengo un documento mongo como este.

{ "_id" : ObjectId("50b429ba0e27b508d854483e"), "array" : [ { "id" : "1", "letter" : "a" }, { "id" : "2", "letter" : "b" } ], "tester" : "tom" } 

Quiero poder insertar y actualizar la array con un solo comando mongo y no usar un condicional dentro de un find() luego ejecutar insert() y update() dependiendo de la presencia del objeto.

La id es el artículo que quiero ser el selector. Entonces, si actualizo la matriz con esto:

 { "id" : "2", "letter" : "c" } 

Tengo que usar una statement de $set

 db.soup.update({ "tester":"tom", 'array.id': '2' }, { $set: { 'array.$.letter': 'c' } }) 

Y si quiero insertar un nuevo objeto en la matriz

 { "id" : "3", "letter" : "d" } 

Tengo que usar una statement $push

 db.soup.update({ "tester":"tom" }, { $push: { 'array': { "id": "3", "letter": "d" } } }) 

Necesito una especie de upsert para un elemento de matriz.

¿Tengo que hacer esto programáticamente o puedo hacerlo con una única llamada mongo?

No estoy al tanto de una opción que pueda guardarse en una matriz incrustada como en MongoDB 2.2, por lo que es probable que deba manejar esto en el código de su aplicación.

Dado que desea tratar el conjunto incrustado como una especie de colección virtual, puede considerar modelar el conjunto como una colección separada.

No puede hacer un upsert basado en un valor de campo dentro de una matriz incrustada, pero podría usar $addToSet para insertar un documento incrustado si aún no existe:

 db.soup.update({ "tester":"tom" }, { $addToSet: { 'array': { "id": "3", "letter": "d" } } }) 

Eso no se ajusta a su caso de uso exacto de coincidencia por id del elemento de matriz, pero puede ser útil si conoce el valor actual esperado.

Me encontré con este problema yo mismo. No pude encontrar una solución de una llamada, pero encontré una solución de dos llamadas que funciona cuando tienes un valor único en los elementos de tu matriz . Primero use el comando $pull , que elimina elementos de una matriz, y luego $push .

 db.soup.update({ "tester":"tom" }, { $pull: { 'array': { "id": "3" } } }) db.soup.update({ "tester":"tom" }, { $push: { 'array': { "id": "3", "letter": "d" } } }) 

Esto debería funcionar cuando el documento no existe, cuando el documento existe pero la entrada en la matriz no existe y cuando existe la entrada.

De nuevo, esto solo funciona si tiene algo, como el campo de id En este ejemplo, que debe ser único en todos los elementos de la matriz.

En algunos casos, puede lograr actualizaciones de conjuntos de documentos integrados si puede reestructurar sus documentos para usar objetos en lugar de matrices. Acabo de responder esto en otra pregunta, pero lo adaptaré aquí por conveniencia.


Un documento de ejemplo sería

 { tester: 'tom', items: { '1': 'a', '2': 'b' } } 

Para insertar un elemento con id 3 y valor ‘c’, harías

 db.coll.update( { tester: 'tom' }, { $set: { 'items.3': 'c' } } ) 

Una desventaja es que la consulta de nombres de campo (utilizando el operador de consulta $exists ) requiere un escaneo. Puede evitar esto agregando un campo de matriz adicional que almacena los nombres de las propiedades. Este campo puede ser indexado y consultado normalmente. Los postres se vuelven

 db.coll.update( { tester: 'tom' }, { $set: { 'items.3': 'c' }, $addToSet: { itemNames: 3 } } ) 

(Tenga en cuenta que $addToSet es O (n).) Al eliminar una propiedad, también debe extraerla de la matriz.

 db.widgets.update( { tester: 'tom' }, { $unset: { 'items.3': true }, $pull: { itemNames: 3 } } )