Pregunta MongoDB: Actualización de documentos utilizando datos del mismo documento [duplicado]


Esta pregunta ya tiene una respuesta aquí:

Tengo una lista de documentos, cada uno con propiedades lat y lon (entre otros).

{ 'lat': 1, 'lon': 2, someotherdata [...] } 
{ 'lat': 4, 'lon': 1, someotherdata [...] }
[...]

Quiero modificarlo para que se vea así:

{ 'coords': {'lat': 1, 'lon': 2}, someotherdata [...]} 
{ 'coords': {'lat': 4, 'lon': 1}, someotherdata [...]}
[...]

Hasta ahora tengo esto:

db.events.update({}, {$set : {'coords': {'lat': db.events.lat, 'lon': db.events.lon}}}, false, true)

Pero trata el db.events.lat y db.events.lon como cadenas. ¿Cómo puedo hacer referencia a las propiedades del documento?

Aclamaciones.


73
2017-09-24 14:52


origen


Respuestas:


los $ rename operador (introducido un mes después de que se publicó esta pregunta) hace que sea realmente fácil hacer este tipo de cosas donde no es necesario modificar los valores.

Inserta algunos documentos de prueba

db.events.insert({ 'lat': 1, 'lon': 2, someotherdata: [] })
db.events.insert({ 'lat': 4, 'lon': 1, someotherdata: [] })

utilizar el $rename operador

db.events.update({}, {$rename: {'lat': 'coords.lat', 'lon': 'coords.lon'}}, false, true)

Resultados

db.events.find()
{
    "_id" : ObjectId("5113c82dd28c4e8b79971add"),
    "coords" : {
        "lat" : 1,
        "lon" : 2
    },
    "someotherdata" : [ ]
}
{
    "_id" : ObjectId("5113c82ed28c4e8b79971ade"),
    "coords" : {
        "lat" : 4,
        "lon" : 1
    },
    "someotherdata" : [ ]
}

53
2018-02-07 15:41



Actualizar: Si todo lo que tiene que hacer es cambiar la estructura de un documento sin cambiar los valores, consulte respuesta del gipset para una buena solución.


De acuerdo con un comentario (ahora no disponible) sobre Actualizar la página de documentación, no puede hacer referencia a las propiedades del documento actual desde dentro de update().

Tendrás que repetir todos los documentos y actualizarlos de esta manera:

db.events.find().snapshot().forEach(
  function (e) {
    // update document, using its own properties
    e.coords = { lat: e.lat, lon: e.lon };

    // remove old properties
    delete e.lat;
    delete e.lon;

    // save the updated document
    db.events.save(e);
  }
)

Tal función también se puede usar en un trabajo de reducción de mapa o en un servidor db.eval() trabajo, dependiendo de tus necesidades.


193
2017-09-25 07:52



Podemos usar la secuencia de comandos de Mongo para manipular datos sobre la marcha. ¡Esto funciona para mi!

Yo uso este script para corregir mis datos de dirección.

Ejemplo de dirección actual: "N ° 12, QUINTA AVENIDA".

Quiero eliminar la última coma redundante, la nueva dirección esperada "" Nº12, QUINTA AVENIDA ".

var cursor = db.myCollection.find().limit(100);

while (cursor.hasNext()) {
  var currentDocument = cursor.next();

  var address = currentDocument['address'];
  var lastPosition = address.length - 1;

  var lastChar = address.charAt(lastPosition);

  if (lastChar == ",") {

    var newAddress = address.slice(0, lastPosition);


    currentDocument['address'] = newAddress;

    db.localbizs.update({_id: currentDocument._id}, currentDocument);

  }
}

¡Espero que esto ayude!


3
2017-11-03 12:53



Siempre que esté de acuerdo con la creación de una copia de los datos, el marco de agregación se puede utilizar como una alternativa aquí. También tiene la opción de hacer más a los datos si desea utilizar otros operadores, pero el único que necesita es $project. Es algo derrochador en términos de espacio, pero puede ser más rápido y más apropiado para algunos usos. Para ilustrar, primero insertaré algunos datos de muestra en el foo colección:

db.foo.insert({ 'lat': 1, 'lon': 2, someotherdata : [1, 2, 3] })
db.foo.insert({ 'lat': 4, 'lon': 1, someotherdata : [4, 5, 6] })

Ahora, solo usamos $project para volver a trabajar el lat y lon campos, luego enviarlos a la newfoo colección:

db.foo.aggregate([
    {$project : {_id : "$_id", "coords.lat" : "$lat", "coords.lon" : "$lon", "someotherdata" : "$someotherdata" }},
    { $out : "newfoo" }
])

Entonces revisa newfoo para nuestros datos alterados:

db.newfoo.find()
{ "_id" : ObjectId("544548a71b5cf91c4893eb9a"), "someotherdata" : [ 1, 2, 3 ], "coords" : { "lat" : 1, "lon" : 2 } }
{ "_id" : ObjectId("544548a81b5cf91c4893eb9b"), "someotherdata" : [ 4, 5, 6 ], "coords" : { "lat" : 4, "lon" : 1 } }

Una vez que esté satisfecho con los nuevos datos, puede usar el renameCollection() comando para soltar los datos antiguos y usar los nuevos datos bajo el nombre anterior:

> db.newfoo.renameCollection("foo", true)
{ "ok" : 1 }
> db.foo.find()
{ "_id" : ObjectId("544548a71b5cf91c4893eb9a"), "someotherdata" : [ 1, 2, 3 ], "coords" : { "lat" : 1, "lon" : 2 } }
{ "_id" : ObjectId("544548a81b5cf91c4893eb9b"), "someotherdata" : [ 4, 5, 6 ], "coords" : { "lat" : 4, "lon" : 1 } }

Una última nota - hasta SERVIDOR-7944 se completa, no puede hacer el equivalente de una instantánea haciendo alusión al _id índice como se sugiere en esta respuesta y así puede terminar golpeando un documento más de una vez si la actividad en otro lugar hace que se mueva. Como está insertando el _id En este ejemplo, cualquier evento de este tipo provocaría una violación de clave única, por lo que no terminará con engaños, pero es posible que tenga una versión "anterior" de un documento. Como siempre, verifique sus datos a fondo antes de soltarlos y, preferiblemente, haga una copia de seguridad.


3
2017-10-20 18:23



Neils responde. Solo para que las personas sepan que no se puede ejecutar esto en una gran base de datos si se permite hacerlo remotamente como Robomongo. Tendrá que ingresar al caparazón de mongo de su servidor real. También podría hacer esto si prefiere hacer una actualización.

db.Collection.find({***/ possible query /***}).toArray().forEach(
  function(obj){
    obj.item = obj.copiedItem;
    obj.otherItem = obj.copiedItem;
    obj.thirdItem = true;
    obj.fourthItem = "string";
    db.Collection.update({_id: obj._id}, obj);
  }
);

3
2017-10-18 15:49



De la CLI? Creo que primero hay que sacar los valores y asignar el valor a una variable. Luego ejecuta tu comando de actualización.

O (no lo he intentado) elimine 'db' de la cadena. events.lat y events.lon Si funciona, todavía tendrá valores múltiples, los valores anteriores para "lat" y "lon" y la nueva matriz que creó.


0
2017-09-24 17:34