2010-11-08 16 views
42

tengo un documento en mongodb con 2 nivel profundo matriz anidada de los objetos que tengo que actualizar, algo como esto:Actualización en mongodb

{ 
    id: 1, 
    items: [ 
     { 
      id: 2, 
      blocks: [ 
       { 
        id: 3 
        txt: 'hello' 
       } 
      ] 
     } 
    ] 
} 

Si sólo había un arsenal nivel profundo que podría utilizar operador posicional para actualizar objetos en ella, pero en el segundo nivel, la única opción que he ocurrió es utilizar el operador posicional con el índice del objeto anidado, como esto:

db.objects.update({'items.id': 2}, {'$set': {'items.$.blocks.0.txt': 'hi'}}) 

este enfoque funciona pero parece peligroso para mí ya que Estoy construyendo un servicio web y un número de índice debería venir de clie nt que puede enviar decir 100000 como índice y esto obligará a mongodb a crear una matriz con 100000 índices con valor nulo.

¿Hay alguna otra forma de actualizar dichos objetos anidados donde pueda consultar el ID del objeto en lugar de su posición o formas de verificar si el índice suministrado está fuera de límites antes de usarlo en la consulta?

+4

Le sugiero que vuelva a visitar este esquema y encuentre un diseño diferente para que pueda aprovechar la potencia que proporciona MongoDB. No va a haber una manera fácil/súper eficiente de actualizar un elemento específico en la matriz AFAIK. ¿Puede rediseñar esto para que pueda aprovechar adavantage de 'addToSet',' pop' y de los otros operadores de matriz? – brianz

+0

Gracias por su sugerencia, sí puedo y, de hecho, ya lo hice. Al hacer esta pregunta solo quería asegurarme de que no me faltaba nada. – Anton

+2

También estoy enfrentando el mismo problema. ¿Puede publicar su muestra de esquema rediseñado? – Damodaran

Respuesta

26

Aquí está la gran pregunta: ¿necesita aprovechar las operaciones de "agregar y configurar" de Mongo? Si realmente planea modificar solo elementos individuales en la matriz, entonces probablemente debería construir estas matrices como objetos.

Así es como me gustaría estructurar esta:

{ 
    id: 1, 
    items: 
     { 
      "2" : { "blocks" : { "3" : { txt : 'hello' } } }, 
      "5" : { "blocks" : { "1" : { txt : 'foo'}, "2" : { txt : 'bar'} } } 
     } 
} 

Esto, básicamente, todo lo transforma en objetos de JSON en lugar de matrices. Pierdes la habilidad de usar $push y $addToSet, pero creo que esto hace que todo sea más fácil. Por ejemplo, la consulta se vería así:

db.objects.update({'items.2': {$exists:true} }, {'$set': {'items.2.blocks.0.txt': 'hi'}})

También notará que He vertido del "identificadores". Cuando anida cosas como esta generalmente puede reemplazar "ID" simplemente usando ese número como índice. El concepto de "ID" ahora está implícito.

Esta característica se ha agregado en 3.6 con expressive updates.

db.objects.update({id: 1 }, { $set: { 'items.$[itm].blocks.$[blk].txt': "hi", } }, { multi: false, arrayFilters: [ { 'itm.id': 2 }, { 'blk.id': 3} ] })

+0

cómo funcionaría es una matriz. – kapad

+0

si 'items' es una matriz, ese comando' $ set' no funciona. Tendrá que estructurar los datos de manera diferente y aprovechar '$ addToSet'. –

+1

Estaba buscando una solución usando el '$'. Algo así como 'items. $' Que iteraría sobre todos los elementos de la matriz de elementos y haría el cambio que yo quisiera. Alguna idea de lo que la sintaxis sería para algo como esto. ¿A caso se puede hacer? – kapad

3

Los identificadores de la que está utilizando son el número lineal y tiene que venir de alguna parte como un campo adicional, 'max_idx' o algo similar. Esto significa una búsqueda para la identificación y luego actualizar. UUID/ObjectId se puede usar para identificadores que garantizarán que también pueda usar Distributed CRUD.

Cuestiones relacionadas