#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. Не удалось внести изменения, чтобы попробовать ваше первое решение, поскольку я использую более старую версию, но второе работает хорошо и выглядит чище, спасибо