2012-04-24 9 views
105

Dado este documento guardado en MongoDB¿Cómo se actualiza parcialmente un objeto en MongoDB por lo que el nuevo objeto se superpondrá/fusionarse con la existente

{ 
    _id : ..., 
    some_key: { 
     param1 : "val1", 
     param2 : "val2", 
     param3 : "val3" 
    } 
} 

Un objeto con nueva información sobre param2 y param3 del mundo exterior necesita ser salvado

var new_info = { 
    param2 : "val2_new", 
    param3 : "val3_new" 
}; 

quiero fusionar/superponer los nuevos campos sobre el estado actual del objeto para que param1 no se eliminan

Hacer esto

db.collection.update( { _id:...} , { $set: { some_key : new_info } } 

dará lugar a MongoDB está haciendo exactamente como se lo pidió, y se pone some_key a ese valor. reemplazando el anterior.

{ 
    _id : ..., 
    some_key: { 
     param2 : "val2_new", 
     param3 : "val3_new" 
    } 
} 

¿Cuál es la manera de tener la actualización MongoDB sólo nuevos campos (sin ellos indicando una por una de forma explícita)? Para conseguir esto:

{ 
    _id : ..., 
    some_key: { 
     param1 : "val1", 
     param2 : "val2_new", 
     param3 : "val3_new" 
    } 
} 

estoy usando el cliente de Java, pero ningún ejemplo se observará

+0

favor votar por el tema de combinación $: https://jira.mongodb.org/browse/SERVER- 21094 – Ali

Respuesta

71

Si entiendo bien la pregunta, desea actualizar un documento con el contenido de otro documento, pero solo los campos que aún no están presentes e ignoran por completo los campos que ya están configurados (incluso si se trata de otro valor).

No hay forma de hacerlo en un solo comando.

Primero tiene que consultar el documento, averiguar qué quiere $set y luego actualizarlo (utilizando los valores anteriores como filtro coincidente para asegurarse de no obtener actualizaciones simultáneas).


Otra lectura de su pregunta sería que usted es feliz con $set, pero no desea establecer explícitamente todos los campos. ¿Cómo pasaría los datos?

usted sabe que puede hacer lo siguiente:

db.collection.update( { _id:...} , { $set: someObjectWithNewData } 
+2

¿Qué sucede si desea establecer explícitamente todos los campos ... – morgs32

+0

Si desea configurar todos los campos de forma incondicional, puede usar [$ multi] (https://docs.mongodb.com/manual/reference/method/ db.collection.parámetro update/# multiparámetro), como este: 'db.collection.update ({_id: ...}, {$ set: someObjectWithNewData, {$ multi: true}})' –

+5

No hay $ multi parámetro. Hay una opción múltiple (que es a lo que se ha vinculado), pero eso no afecta la forma en que se actualizan los campos. Controla si actualiza un único documento o todos los documentos que coinciden con el parámetro de consulta. –

1

Parece que puedes configurar isPartialObject que podría lograr lo que deseas.

+0

lo intenté. no me permite guardar objetos parciales si no me equivoco ... pero gracias –

69

Lo resolví con mi propia función. Si desea actualizar el campo especificado en el documento, debe abordarlo con claridad.

Ejemplo:

{ 
    _id : ..., 
    some_key: { 
     param1 : "val1", 
     param2 : "val2", 
     param3 : "val3" 
    } 
} 

Si desea actualizar param2 única, que está mal hacer:

db.collection.update( { _id:...} , { $set: { some_key : new_info } } //WRONG 

debe utilizar:

db.collection.update( { _id:...} , { $set: { some_key.param2 : new_info } } 

así que escribí una función algo así:

+7

Esta debería ser la respuesta aceptada. Para una mejor función de flattenObject, vea https://gist.github.com/penguinboy/762197 – steph643

+0

Gracias su respuesta me ayudó a guiarme. Pude modificar el valor de una clave específica de un usuario en la colección de usuarios de la siguiente manera: 'db.users.update ({_id: ObjectId (" 594dbc3186bb5c84442949b1 ")}, {$ set: {resume: {url:" http://i.imgur.com/UFX0yXs.jpg "}}})' –

8

Puede usar la notación de puntos para acceder y establecer campos en el interior de los objetos, sin afectar las otras propiedades de esos objetos.

Teniendo en cuenta el objeto que ha especificado arriba:

> db.test.insert({"id": "test_object", "some_key": {"param1": "val1", "param2": "val2", "param3": "val3"}}) 
WriteResult({ "nInserted" : 1 }) 

podamos actualizar simplemente some_key.param2 y some_key.param3:

> db.test.findAndModify({ 
... query: {"id": "test_object"}, 
... update: {"$set": {"some_key.param2": "val2_new", "some_key.param3": "val3_new"}}, 
... new: true 
... }) 
{ 
    "_id" : ObjectId("56476e04e5f19d86ece5b81d"), 
    "id" : "test_object", 
    "some_key" : { 
     "param1" : "val1", 
     "param2" : "val2_new", 
     "param3" : "val3_new" 
    } 
} 

Puede ahondar tan profundamente como usted quiera. Esto también es útil para agregar nuevas propiedades a un objeto sin afectar las existentes.

1

Había éxito hacerlo de esta manera:

db.collection.update( { _id:...} , { $set: { 'key.another_key' : new_info } }); 

Tengo una función que se encarga de perfil actualiza dinámicamente

function update(prop, newVal) { 
    const str = `profile.${prop}`; 
    db.collection.update({ _id:...}, { $set: { [str]: newVal } }); 
} 

Nota: 'perfil' es específico de mi aplicación, se es solo la cadena de la tecla que desea modificar.

6

La mejor solución es extraer propiedades del objeto y convertirlas en pares de pares clave-valor de notación de puntos planos. Se podría utilizar, por ejemplo, esta biblioteca:

https://www.npmjs.com/package/mongo-dot-notation

Tiene .flatten función que le permite cambiar objeto en conjunto plana de propiedades que podrían darse luego a $ fijar modificador, sin preocupaciones de que cualquier propiedad de su actual El objeto DB se borrará/sobrescribirá sin necesidad.

Tomado de mongo-dot-notation docs:

var person = { 
    firstName: 'John', 
    lastName: 'Doe', 
    address: { 
    city: 'NY', 
    street: 'Eighth Avenu', 
    number: 123 
    } 
}; 



var instructions = dot.flatten(person) 
console.log(instructions); 
/* 
{ 
    $set: { 
    'firstName': 'John', 
    'lastName': 'Doe', 
    'address.city': 'NY', 
    'address.street': 'Eighth Avenu', 
    'address.number': 123 
    } 
} 
*/ 

Y entonces se forma el selector perfecta - se actualizará sólo las propiedades dadas. EDIT: me gusta ser arqueólogo algunas veces;)

+0

funcionó como un encanto, gracias! – caffeinescript

0

uso $ conjunto hacer este proceso

.update({"_id": args.dashboardId, "viewData._id": widgetId}, {$set: {"viewData.$.widgetData": widgetDoc.widgetData}}) 
.exec() 
.then(dashboardDoc => { 
    return { 
     result: dashboardDoc 
    }; 
}); 
Cuestiones relacionadas