集合中有以下文档:
const documents = [
{
_id: '1',
items: [
{
type: 'plastic',
color: 'blue',
date: '2021-02-01',
oldValues: [{ color: 'light-blue', date: '2021-01-01' }],
},
{
type: 'plastic',
color: 'black',
date: '2021-03-01',
oldValues: [
{ color: 'white', date: '2021-01-01' },
{ color: 'grey', date: '2021-02-01' },
],
},
],
},
{
_id: '2',
items: [
{
type: 'plastic',
color: 'violet',
date: '2021-02-01',
oldValues: [{ color: 'pink', date: '2021-01-01' }],
},
{
type: 'wood',
color: 'black',
date: '2021-03-01',
oldValues: [
{ color: 'white', date: '2021-01-01' },
{ color: 'orange', date: '2021-02-01' },
],
},
],
},
];
我想在 items 字段中查找包含类型为 Plastic 且颜色为 black 的项目的文档,将该项目的颜色更新为 green,并在 oldValues 中保留当前项目的记录 字段,像这样:
[
{
_id: '1',
items: [
{
type: 'plastic',
color: 'blue',
date: '2021-02-01',
oldValues: [{ color: 'light-blue', date: '2021-01-01' }],
},
{
type: 'plastic',
color: 'green',
date: '2021-03-01',
oldValues: [
{ color: 'white', date: '2021-01-01' },
{ color: 'grey', date: '2021-02-01' },
{ color: 'black', date: '2021-03-01' },
],
},
],
},
{
_id: '2',
items: [
{
type: 'plastic',
color: 'violet',
date: '2021-02-01',
oldValues: [{ color: 'pink', date: '2021-01-01' }],
},
{
type: 'wood',
color: 'black',
date: '2021-03-01',
oldValues: [
{ color: 'white', date: '2021-01-01' },
{ color: 'orange', date: '2021-02-01' },
],
},
],
},
];
为此,我编写并运行了以下查询:
db.collection.update(
{ items: { $elemMatch: { color: 'black', type: 'plastic' } } },
{
$set: {
'items.$[item].color': 'green',
'items.$[item].date': '2021-04-01',
'items.$[item].oldValues': {
$concatArrays: [
{ $ifNull: ['$items.$[item].oldValues', []] },
[{ color: '$items.$[item].color', date: '$items.$[item].date' }],
],
},
},
},
{ arrayFilters: [{ 'item.color': 'black', 'item.type': 'plastic' }] },
);
通过此查询,items字段中感兴趣项目的color字段已更新,但oldValues字段被更新项覆盖:
const updatedDocumentsAfterRunningQuery = [
{
_id: '1',
items: [
{
color: 'blue',
date: '2021-02-01',
oldValues: [{ color: 'light-blue', date: '2021-01-01' }],
type: 'plastic',
},
{
color: 'green',
date: '2021-04-01',
oldValues: {
$concatArrays: [
{ $ifNull: ['$items.$[item].oldValues', []] },
[{ color: '$items.$[item].color', date: '$items.$[item].date' }],
],
},
type: 'plastic',
},
],
},
{
_id: '2',
items: [
{
color: 'violet',
date: '2021-02-01',
oldValues: [{ color: 'pink', date: '2021-01-01' }],
type: 'plastic',
},
{
color: 'black',
date: '2021-03-01',
oldValues: [
{ color: 'white', date: '2021-01-01' },
{ color: 'orange', date: '2021-02-01' },
],
type: 'wood',
},
],
},
];
看起来运算符 $concatArrays 未被 $set 运算符检测到。
这是MongoDb Playground的链接。
我该如何解决这个问题?
请尝试一下此代码:
db.collection.aggregate([
{
$match: {
"items.color": "black",
"items.type": "plastic"
}
},
{
$set: {
items: {
$map: {
input: "$items",
as: "item",
in: {
$cond: {
if: {
$and: [
{
$eq: [
"$$item.color",
"black"
]
},
{
$eq: [
"$$item.type",
"plastic"
]
}
]
},
then: {
$mergeObjects: [
"$$item",
{
color: "green",
date: "2021-04-01",
oldValues: {
$concatArrays: [
{
$ifNull: [
"$$item.oldValues",
[]
]
},
[
{
color: "$$item.color",
date: "$$item.date"
}
]
]
}
}
]
},
else: "$$item"
}
}
}
}
}
},
{
$merge: {
into: "collection",
whenMatched: "replace"
}
}
])