为了清楚地说明问题,让我从一个例子开始。
假设我们有一系列产品,其中一种产品可以有多个品牌并在不同的商店出售,每个商店可以销售该产品的一个或多个品牌:
{
"name": "Pen",
"shops": [
{
"name": "Target",
"brands": [
"BIC"
]
},
{
"name": "Walmart",
"brands": [
"Parker"
]
}
],
"brands": [
{
"name": "BIC"
},
{
"name": "Parker"
}
]
}
但是,由于不可预见的情况,我们不能再使用品牌名称作为参考,而应该使用其他标识符。 但是,我们必须更新集合中的所有现有文档,使其具有如下所示的内容:
{
"name": "Pen",
"shops": [
{
"name": "Target",
"brands": [
"1"
]
},
{
"name": "Walmart",
"brands": [
"2"
]
}
],
"brands": [
{
"id": "1"
"name": "BIC"
},
{
"id": "2"
"name": "Parker"
}
]
}
向品牌添加 id 相对容易,但更换商店内的品牌才是真正的问题。
mongodb 中有没有办法更新商店子文档以使用商店的 id 而不是名称?
类似:
db.products.updateMany({},
{
$set: {
"shops.brands.$" : "$brands[name=$].id"
}
}
)
所以这里有一个更新命令可以实现你想要的。
首先,
$map
每个品牌都有基于其索引加1的结构和ID。
$add: [..., 1]
。$toString: {}
放在 $indexOfArray: {}
部分周围。其次,还
$map
每个商店,并根据其索引为每个商店品牌嵌套一个$map
。 id 将与上面相同,因为它们是在相同的 $set
步骤中完成的 - 因此 "$brands"
指的是 文档中的当前值,而不是上面设置的值。 (你甚至可以将两者颠倒,结果是一样的。)
db.products.update({},
[
{
$set: {
// create new brandIDs based on index
"brands": {
$map: {
input: "$brands",
as: "brand",
in: {
"name": "$$brand.name",
"id": {
$add: [
{ $indexOfArray: ["$brands", "$$brand"] },
1
]
}
}
}
},
// also create shop-brandIDs based on their index
"shops": {
$map: {
input: "$shops",
as: "shop",
in: {
"name": "$$shop.name",
"brands": {
$map: {
input: "$$shop.brands",
as: "shop_brand",
in: {
$add: [
{ $indexOfArray: ["$brands", { "name": "$$shop_brand" }] },
1
]
}
}
}
}
}
}
}
}
],
{ multi: true }
)
注:
updateMany
;我仅将 update
与 {multi: true}
用于 Mongo 游乐场。另外,您可能不需要管道语法数组[]
,因为它只是一个$set
步骤,但如果没有它,它就无法在游乐场上工作。