es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

MongoDB empuje el valor existente de un campo a otro campo en un array de objetos.

Si tengo un documento como este:

db.people.insertOne({name: "Annie", latestScore: 5});

Entonces, basándome en esta respuesta, puedo mover latestScore a un campo de array de la siguiente manera:

db.people.updateOne(
    {name: 'Annie'},
    [
        {$set: 
            {scoreHistory: 
                {$concatArrays: [
                    {$ifNull: ["$scoreHistory", []]},
                    ["$latestScore"]
                ]}
            }
        }, 
        { $unset: ["latestScore"] }
    ]
);

Este es el documento resultante:

{
  _id: ObjectId("61d2737611e48e0d0c30b35b"),
  name: 'Annie',
  scoreHistory: [ 5 ]
}

¿Podemos realizar la misma actualización en objetos anidados en un array? Por ejemplo, si el documento es así:

db.people.insertOne({
    name: 'Annie',
    words: [
        {word: "bunny", score: 5},
        {word: "pink", score: 5}
    ]
});

¿Cómo podemos actualizarlo a esto?

{
    name: 'Annie',
    words: [
        {word: "bunny", scoreHistory: [5]},
        {word: "pink", scoreHistory: [5]}
    ]
}

Sé que puedo iterar y modificar el array desde la aplicación y actualizar el array completo de una vez, pero me gustaría hacerlo usando operadores como en el primer ejemplo anterior.

El sitio web muestra primero words.word y words.score en filas, al hacer clic en una fila se muestra words.scoreHistory en un popup. Espero que el array de palabras tenga menos de 500 elementos. ¡Cualquier consejo sobre remodelar el esquema para simplificar la operación anterior también es bienvenido!

Tags:  ,

Answer

  1. Avatar for davy.ai

    Sí, podemos realizar la misma actualización a objetos anidados en un arreglo utilizando el operador posicional $[<identificador>]. Así es cómo podemos actualizar el documento dado:

    db.people.updateOne(
        {nombre: 'Annie', 'words.word': 'bunny'},
        [
            {$set: {'words.$[elem].scoreHistory': 
                {$concatArrays: [
                    {$ifNull: ['$words.$[elem].scoreHistory', []]},
                    ['$words.$[elem].score']
                ]}
            }},
            { $unset: ['words.$[elem].score'] }
        ],
        { arrayFilters: [ { 'elem.word': 'bunny' } ] }
    )
    

    Esto establecerá el campo scoreHistory como un arreglo que contiene el valor anterior de score y el nuevo latestScore.

    En la consulta anterior, estamos utilizando el operador posicional $[<identificador>] para identificar el elemento coincidente en el arreglo words utilizando la opción arrayFilters. Luego, estamos utilizando los operadores $ifNull y $concatArrays para actualizar el campo scoreHistory y eliminar el campo score.

    Para simplificar la operación, podemos considerar mover el subdocumento words a su propia colección y realizar las actualizaciones utilizando una consulta separada. Esto también mejorará el rendimiento de la consulta, ya que no tendremos que actualizar el documento completo por cada actualización de palabra.

Comments are closed.