mongodb update subdocument array
Mongodb actualiza el subdocumento profundamente anidado (9)
Compartiendo mis lecciones aprendidas. Me enfrenté al mismo requisito recientemente donde necesito actualizar un elemento de matriz anidada. Mi estructura es la siguiente
{
"main": {
"id": "ID_001",
"name": "Fred flinstone Inc"
},
"types": [
{
"typeId": "TYPE1",
"locations": [
{
"name": "Sydney",
"units": [
{
"unitId": "PHG_BTG1"
}
]
},
{
"name": "Brisbane",
"units": [
{
"unitId": "PHG_KTN1"
},
{
"unitId": "PHG_KTN2"
}
]
}
]
}
]
}
Mi requisito es agregar algunos campos en unidades específicas []. Mi solución es primero encontrar el índice del elemento de matriz anidado (digamos foundUnitIdx). Las dos técnicas que utilicé son
- usa la palabra clave $ set
especifique el campo dinámico en $ set usando la sintaxis []
query = { "locations.units.unitId": "PHG_KTN2" }; var updateItem = { $set: { ["locations.$.units."+ foundUnitIdx]: unitItem } }; var result = collection.update( query, updateItem, { upsert: true } );
Espero que esto ayude a otros. :)
Tengo una estructura de documento profundamente anidada, como esta:
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{ level: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{ level: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]
}
Estoy tratando de actualizar la colección para insertar una nueva configuración, que se ve así:
newdata = {
config: "Custom 1",
variables: [{ x: 111, y:2222, z:3333}]
}
Estoy intentando algo como esto en mongo (en Python):
db.myCollection.update({"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.$.configs.$": newData}}
)
Sin embargo, recibo el mensaje "No se puede aplicar el operador posicional sin un campo de consulta correspondiente que contenga una matriz". ¿Cuál es la forma correcta de hacer esto en mongo? Esto es mongo v2.4.1.
Dado que MongoDB no parece proporcionar un buen mecanismo para esto, me parece prudente usar mangosta para simplemente extraer el elemento de la colección mongo usando .findOne(...)
, ejecutar una búsqueda for-loop en sus correspondientes subelementos. (buscando, por ejemplo, ObjectID), modifique ese JSON, luego haga Schema.markModified(''your.subdocument''); Schema.save();
Schema.markModified(''your.subdocument''); Schema.save();
Probablemente no sea eficiente, pero es muy simple y funciona bien.
Desafortunadamente, no puede usar el operador $
más de una vez por clave, por lo que debe usar valores numéricos para el resto. Como en:
db.myCollection.update({
"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.0.configs.0": newData}}
)
El soporte de MongoDB para actualizar matrices anidadas es pobre. Por lo tanto, es mejor que evite su uso si necesita actualizar los datos con frecuencia, y considere usar múltiples colecciones en su lugar.
Una posibilidad: hacer forecasts
su propia colección, y suponiendo que tiene un conjunto fijo de valores de level
, haga que el level
un objeto en lugar de una matriz:
{
_id: 123,
parentId: 1,
name: "Forecast 1",
levels: {
proven: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
likely: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
}
}
Luego puedes actualizarlo usando:
db.myCollection.update({
_id: 123,
''levels.proven.configs.config'': ''Custom 1''
},
{ $set: { ''levels.proven.configs.$'': newData }}
)
Está arreglado. https://jira.mongodb.org/browse/SERVER-831
Pero esta característica está disponible comenzando con la versión de desarrollo MongoDB 3.5.12.
Nota: Esta pregunta se realizó el Aug 11 2013
y se resolvió el Aug 11 2017
Este es un error muy VIEJO en MongoDB
Logré resolverlo con el uso de la mangosta:
Todo lo que necesita saber es el''id de todo el subdocumento de la cadena (mangosta crea automáticamente ''_id'' para cada subdocumento).
por ejemplo -
SchemaName.findById(_id, function (e, data) {
if (e) console.log(e);
data.sub1.id(_id1).sub2.id(_id2).field = req.body.something;
// or if you want to change more then one field -
//=> var t = data.sub1.id(_id1).sub2.id(_id2);
//=> t.field = req.body.something;
data.save();
});
Más sobre el sub-documento _id método en la documentación de mangosta .
explicación: _id es para SchemaName, _id1 para sub1 y _id2 para sub2 - puede seguir encadenando así.
* No tiene que usar el método findById, pero me parece el más conveniente ya que necesita saber el resto del''id de todos modos.
MongoDB ha introducido ArrayFilters para abordar este problema en la versión 3.5.2 y posteriores.
Nuevo en la versión 3.6.
Comenzando en MongoDB 3.6, al actualizar un campo de matriz, puede especificar los filtros de matriz que determinan qué elementos de la matriz actualizar.
Digamos que el diseño del esquema es el siguiente:
var ProfileSchema = new Schema({
name: String,
albums: [{
tour_name: String,
images: [{
title: String,
image: String
}]
}]
});
Y el documento creado se ve así:
{
"_id": "1",
"albums": [{
"images": [
{
"title": "t1",
"url": "url1"
},
{
"title": "t2",
"url": "url2"
}
],
"tour_name": "london-trip"
},
{
"images": [.........]:
}]
}
Digamos que quiero actualizar la "url" de una imagen. Dado - "document id", "tour_name" and "title"
Para esto la consulta de actualización:
Profiles.update({_id : req.body.id},
{
$set: {
''albums.$[i].images.$[j].title'': req.body.new_name
}
},
{
arrayFilters: [
{
"i.tour_name": req.body.tour_name, "j.image": req.body.new_name // tour_name - current tour name, new_name - new tour name
}]
})
.then(function (resp) {
console.log(resp)
res.json({status: ''success'', resp});
}).catch(function (err) {
console.log(err);
res.status(500).json(''Failed'');
})
FÁCIL SOLUCIÓN PARA Mongodb 3.2+ https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/
Tuve una situación similar y la resolví así. Estaba usando mangosta, pero todavía debería funcionar en MongoDB. Espero que sea útil para alguien.
const MyModel = require(''./model.js'')
const query = {id: 1}
// First get the doc
MyModel.findOne(query, (error, doc) => {
// Do some mutations
doc.foo.bar.etc = ''some new value''
// Pass in the mutated doc and replace
MyModel.replaceOne(query, doc, (error, newDoc) => {
console.log(''It worked!'')
})
}
Dependiendo de su caso de uso, es posible que pueda omitir el findOne inicial ()
Okkk. Podemos actualizar nuestro subdocumento anidado en mongodb. Este es nuestro esquema.
var Post = new mongoose.Schema({
name:String,
post:[{
like:String,
comment:[{
date:String,
username:String,
detail:{
time:String,
day:String
}
}]
}]
})
solución para este esquema
Test.update({"post._id":"58206a6aa7b5b99e32b7eb58"},
{$set:{"post.$.comment.0.detail.time":"aajtk"}},
function(err,data){
//data is updated
})