使用字段的值并将其添加到数组中的新字段 - Mongodb
Use a field's value and add it to a new field in an array - Mongodb
我正在尝试打开这个
{
"fooList" : [
{
"bar" : {
"baz" : 100
}
},
{
"bar" : {
"baz" : 200
}
}
]
},
{
"fooList" : [
{
"bar" : {
"baz" : 300
}
},
{
"bar" : {
"baz" : 400
}
}
]
}
进入这个:
{
"fooList" : [
{
"baz" : 100,
"bar" : {
"baz" : 100
}
},
{
"baz" : 200,
"bar" : {
"baz" : 200
}
}
]
},
{
"fooList" : [
{
"baz" : 300,
"bar" : {
"baz" : 300
}
},
{
"baz" : 400,
"bar" : {
"baz" : 400
}
}
]
}
如您所见,我实际上只是将 baz
及其值从 bar
中复制出来,但我的问题是它发生在一个数组中。
db.getCollection(<collection_name>).updateMany(
{},
{ $set: { 'fooList.$[element].baz' : '$fooList.$[element].bar.baz' } },
{ upsert: true ,
arrayFilters: [{'element.bar' : { $exists : true }}]
}
)
但是这样只会把字符串$fooList.$[element].bar.baz
设置成baz,通过这里看到的结果
[
{
"_id": ObjectId("5a934e000102030405000000"),
"fooList": [
{
"bar": {
"baz": 100
},
"baz": "$fooList.$[element].bar.baz"
}
]
}
]
任何人都可以告诉我我可能做错了什么,或者这是否可能?谢谢
您可以在 mongoDB 4.2+ 的更新中使用聚合管道,如下所示:
db.collection.update({},
[
{
$set: {
fooList: {
$map: {
input: "$fooList",
in: {
$mergeObjects: [
"$$this",
{
$cond: [
{
$ne: [
"$$this.bar.baz",
undefined
]
},
{
baz: "$$this.bar.baz"
},
{}
]
}
]
}
}
}
}
}
],
{
multi: true
})
解释:
- 你 $set $map-ping 数组记录并根据嵌套元素“bar.baz”存在的条件合并,然后添加对象 baz 等于取自 [=31= 的值].
- 添加 multi:true 为匹配更新查询过滤器的所有文档完成,或者您可以使用 updateMany()
不幸的是,当您将更新与聚合管道一起使用时,arrayFilters 是不可能的...
对于早期的 mongodb 版本,它看起来像这样:
db.collection.find({}).forEach(function(d){ var newfooList=[];d.fooList.forEach(function(s){ s["baz"]=s["bar"]["baz"]; printjson(s);newfooList.push(s); }); d["fooList"]=newfooList ; db.collection.save(d) })
这是一个变体,它演示了将 aggregate
变成 update
的 v4.4“合并到自身”功能。当您想处理所有文档时,这是一种有用的方法,因为它消除了 update
.
所需的“无过滤器”({}
)和 {multi:true}
位
db.foo.aggregate([
// The $map/$mergeObjects is the SAME as the answer above, just with a little
// more compact format. It is import to $project here, NOT $addFields, because
// we seek to limit the pipeline to just _id (comes along automatically) and
// the fooList:
{$project: {
fooList: {$map: {
input: "$fooList",
in: {$mergeObjects: [
"$$this",
{$cond: [
{$ne: ["$$this.bar.baz", undefined]},
{baz: "$$this.bar.baz"},
{} // else empty object
]}
]}
}}
}}
// ...and now, using _id as the key (fast!), merge fooList back into doc:
,{$merge: {
into: "foo",
on: [ "_id" ],
whenMatched: "merge",
whenNotMatched: "fail"
}}
]);
我正在尝试打开这个
{
"fooList" : [
{
"bar" : {
"baz" : 100
}
},
{
"bar" : {
"baz" : 200
}
}
]
},
{
"fooList" : [
{
"bar" : {
"baz" : 300
}
},
{
"bar" : {
"baz" : 400
}
}
]
}
进入这个:
{
"fooList" : [
{
"baz" : 100,
"bar" : {
"baz" : 100
}
},
{
"baz" : 200,
"bar" : {
"baz" : 200
}
}
]
},
{
"fooList" : [
{
"baz" : 300,
"bar" : {
"baz" : 300
}
},
{
"baz" : 400,
"bar" : {
"baz" : 400
}
}
]
}
如您所见,我实际上只是将 baz
及其值从 bar
中复制出来,但我的问题是它发生在一个数组中。
db.getCollection(<collection_name>).updateMany(
{},
{ $set: { 'fooList.$[element].baz' : '$fooList.$[element].bar.baz' } },
{ upsert: true ,
arrayFilters: [{'element.bar' : { $exists : true }}]
}
)
但是这样只会把字符串$fooList.$[element].bar.baz
设置成baz,通过这里看到的结果
[
{
"_id": ObjectId("5a934e000102030405000000"),
"fooList": [
{
"bar": {
"baz": 100
},
"baz": "$fooList.$[element].bar.baz"
}
]
}
]
任何人都可以告诉我我可能做错了什么,或者这是否可能?谢谢
您可以在 mongoDB 4.2+ 的更新中使用聚合管道,如下所示:
db.collection.update({},
[
{
$set: {
fooList: {
$map: {
input: "$fooList",
in: {
$mergeObjects: [
"$$this",
{
$cond: [
{
$ne: [
"$$this.bar.baz",
undefined
]
},
{
baz: "$$this.bar.baz"
},
{}
]
}
]
}
}
}
}
}
],
{
multi: true
})
解释:
- 你 $set $map-ping 数组记录并根据嵌套元素“bar.baz”存在的条件合并,然后添加对象 baz 等于取自 [=31= 的值].
- 添加 multi:true 为匹配更新查询过滤器的所有文档完成,或者您可以使用 updateMany()
不幸的是,当您将更新与聚合管道一起使用时,arrayFilters 是不可能的...
对于早期的 mongodb 版本,它看起来像这样:
db.collection.find({}).forEach(function(d){ var newfooList=[];d.fooList.forEach(function(s){ s["baz"]=s["bar"]["baz"]; printjson(s);newfooList.push(s); }); d["fooList"]=newfooList ; db.collection.save(d) })
这是一个变体,它演示了将 aggregate
变成 update
的 v4.4“合并到自身”功能。当您想处理所有文档时,这是一种有用的方法,因为它消除了 update
.
{}
)和 {multi:true}
位
db.foo.aggregate([
// The $map/$mergeObjects is the SAME as the answer above, just with a little
// more compact format. It is import to $project here, NOT $addFields, because
// we seek to limit the pipeline to just _id (comes along automatically) and
// the fooList:
{$project: {
fooList: {$map: {
input: "$fooList",
in: {$mergeObjects: [
"$$this",
{$cond: [
{$ne: ["$$this.bar.baz", undefined]},
{baz: "$$this.bar.baz"},
{} // else empty object
]}
]}
}}
}}
// ...and now, using _id as the key (fast!), merge fooList back into doc:
,{$merge: {
into: "foo",
on: [ "_id" ],
whenMatched: "merge",
whenNotMatched: "fail"
}}
]);