MongoDB $ отключает каждый объект, соответствующий идентификатору в массиве

#javascript #mongodb

#javascript #mongodb

Вопрос:

Вот как выглядят мои документы:

 {
  id: 123,
  tasks: {
    5f6effae74a3802fe80d02a4: Object
    5f6f289b73cc4e43546733bb: Object
    5f6f28d873cc4e43546733bc: Object
    5f6f291073cc4e43546733bd: Object,
    5f6f291073cc4e43541211cc: Object,
    5f6f291073cc4e43465662eq: Object
  },
  taskIds: [
    5f6effae74a3802fe80d02a4, 
    5f6f289b73cc4e43546733bb, 
    5f6f28d873cc4e43546733bc, 
    5f6f291073cc4e43546733bd
  ]
}
  

Мне нужно удалить каждый объект, tasks который соответствует id из taskIds , поэтому я подумал о сопоставлении taskIds следующим образом:

 const tasksDocument = await db.collection.findOne({id: 123})
tasksDocument.taskIds.map(async (id) => await tasksDocument.updateOne({ $unset: { [`tasks.${[id]}`]: "" } }))
  

Но мне интересно, есть ли более чистый способ сделать это без сопоставления?

Ответ №1:

Если вы используете Mongo версии 4.2 , вы можете использовать конвейерное обновление, которое позволяет вам использовать операторы агрегации в обновлении.

Наша стратегия будет заключаться в преобразовании объекта в массив, фильтрации его с taskIds помощью, а затем обратном преобразовании в объект, мы достигнем этого, используя такие операторы, как $arrayToObject , $objectToArray , $filter и другие.

 db.collection.update(
    {
        'id': 123
    },
    [
        {
            '$set': {
                tasks: {
                    $arrayToObject: {
                        $filter: {
                            input: {$objectToArray: '$tasks'},
                            as: 'task',
                            cond: {
                                $eq: [
                                    {
                                        $size: {
                                            $setIntersection: [['$$task.k'], '$taskIds']       
                                        }
                                    },
                                    0
                                ] 
                            }
                        }
                    }
                }
            }
        }
    ])
  

Для более старых версий Mongo вам нужно разделить это на 2 вызова и выполнить это в коде, аналогичном вашему решению (просто один вызов $unset вместо нескольких).

 const tasksDocument = await db.collection.findOne({id: 123});
let unsetArr = tasksDocument.taskIds.map(v => `tasks.${v}`);
await db.collection.updateOne({id: 123}, {$unset: unsetArr});
  

Комментарии:

1. Не удалось внести изменения, чтобы попробовать ваше первое решение, поскольку я использую более старую версию, но второе работает хорошо и выглядит чище, спасибо