如何使用 $set 和点表示法使用相应的旧元素更新嵌入的数组元素?
How to use $set and dot notation to update embedded array elements using corresponding old element?
我在 MongoDb 中有以下文件:
from pymongo import MongoClient
client = MongoClient(host='my_host', port=27017)
database = client.forecast
collection = database.regions
collection.delete_many({})
regions = [
{
'id': 'DE',
'sites': [
{
'name': 'paper_factory',
'energy_consumption': 1000
},
{
'name': 'chair_factory',
'energy_consumption': 2000
},
]
},
{
'id': 'FR',
'sites': [
{
'name': 'pizza_factory',
'energy_consumption': 3000
},
{
'name': 'foo_factory',
'energy_consumption': 4000
},
]
}
]
collection.insert_many(regions)
现在我想将 属性 sites.energy_consumption
复制到每个站点的新字段 sites.new_field
:
set_stage = {
"$set": {
"sites.new_field": "$sites.energy_consumption"
}
}
pipeline = [set_stage]
collection.aggregate(pipeline)
但是,不是复制每个站点的单个值,而是收集所有站点值并添加为数组。 Intead of 'new_field': [1000, 2000] 我想为第一个站点获取 'new_field': 1000:
{
"_id": ObjectId("61600c11732a5d6b103ba6be"),
"id": "DE",
"sites": [
{
"name": "paper_factory",
"energy_consumption": 1000,
"new_field": [
1000,
2000
]
},
{
"name": "chair_factory",
"energy_consumption": 2000,
"new_field": [
1000,
2000
]
}
]
},
{
"_id": ObjectId("61600c11732a5d6b103ba6bf"),
"id": "FR",
"sites": [
{
"name": "pizza_factory",
"energy_consumption": 3000,
"new_field": [
3000,
4000
]
},
{
"name": "foo_factory",
"energy_consumption": 4000,
"new_field": [
3000,
4000
]
}
]
}
=> 什么表达式可以只使用数组对应的条目?
是否有某种当前索引运算符:
$sites[<current_index>].energy_consumption
或 替代点运算符 (会提醒我 * 乘法和 .* 元素矩阵乘法之间的区别)?
$sites:energy_consumption
或者这是一个错误?
编辑
我也尝试使用“$”positional operator,例如与
sites.$.new_field
或
$sites.$.energy_consumption
但是我得到了错误
FieldPath field names may not start with '$'
相关:
In MongoDB how do you use $set to update a nested value/embedded document?
使用$addFields
db.collection.update({},
[
{
"$addFields": {
"sites": {
$map: {
input: "$sites",
as: "s",
in: {
name: "$$s.name",
energy_consumption: "$$s.energy_consumption",
new_field: {
$map: {
input: "$sites",
as: "value",
in: "$$value.energy_consumption"
}
}
}
}
}
}
}
])
我发现以下设置完整 sites
而不是仅使用点符号指定新字段的丑陋解决方法:
a) 基于javascript函数
set_stage = {
"$set": {
"sites": {
"$function": {
"body": "function(sites) {return sites.map(site => {site.new_field = site.energy_consumption_in_mwh; return site})}",
"args": ["$sites"],
"lang": "js"
}
}
}
}
b) 基于地图和mergeObjects
set_stage = {
"$set": {
"sites": {
"$map": {
"input": "$sites",
"in": {
"$mergeObjects": ["$$this", {
"new_field": "$$this.energy_consumption_in_mwh"
}]
}
}
}
}
}
如果点运算符表达式有某种 $$this 上下文,允许更优雅的解决方案,请告诉我。
如果通过选择该字段是数组的成员,您将选择所有这些字段。
{ar :[{"a" : 1}, {"a" : 2}]}
"$ar.a" = [1 ,2]
此外,您不能将更新运算符与聚合混合使用,您不能使用诸如
$sites.$.energy_consumption
,如果要进行聚合,则必须使用聚合运算符,只有 $match
阶段可以使用查询运算符。
查询
- 与您使用
$setField
的解决方案略有不同
- 我想它会更快,但可能差别不大
- 不用javascript会比较慢
- 这是>=MongoDB5的解,
$setField
是new运算符
aggregate(
[{"$set":
{"sites":
{"$map":
{"input":"$sites",
"in":
{"$setField":
{"field":"new_field",
"input":"$$this",
"value":"$$this.energy_consumption"}}}}}}]
)
我在 MongoDb 中有以下文件:
from pymongo import MongoClient
client = MongoClient(host='my_host', port=27017)
database = client.forecast
collection = database.regions
collection.delete_many({})
regions = [
{
'id': 'DE',
'sites': [
{
'name': 'paper_factory',
'energy_consumption': 1000
},
{
'name': 'chair_factory',
'energy_consumption': 2000
},
]
},
{
'id': 'FR',
'sites': [
{
'name': 'pizza_factory',
'energy_consumption': 3000
},
{
'name': 'foo_factory',
'energy_consumption': 4000
},
]
}
]
collection.insert_many(regions)
现在我想将 属性 sites.energy_consumption
复制到每个站点的新字段 sites.new_field
:
set_stage = {
"$set": {
"sites.new_field": "$sites.energy_consumption"
}
}
pipeline = [set_stage]
collection.aggregate(pipeline)
但是,不是复制每个站点的单个值,而是收集所有站点值并添加为数组。 Intead of 'new_field': [1000, 2000] 我想为第一个站点获取 'new_field': 1000:
{
"_id": ObjectId("61600c11732a5d6b103ba6be"),
"id": "DE",
"sites": [
{
"name": "paper_factory",
"energy_consumption": 1000,
"new_field": [
1000,
2000
]
},
{
"name": "chair_factory",
"energy_consumption": 2000,
"new_field": [
1000,
2000
]
}
]
},
{
"_id": ObjectId("61600c11732a5d6b103ba6bf"),
"id": "FR",
"sites": [
{
"name": "pizza_factory",
"energy_consumption": 3000,
"new_field": [
3000,
4000
]
},
{
"name": "foo_factory",
"energy_consumption": 4000,
"new_field": [
3000,
4000
]
}
]
}
=> 什么表达式可以只使用数组对应的条目?
是否有某种当前索引运算符:
$sites[<current_index>].energy_consumption
或 替代点运算符 (会提醒我 * 乘法和 .* 元素矩阵乘法之间的区别)?
$sites:energy_consumption
或者这是一个错误?
编辑
我也尝试使用“$”positional operator,例如与
sites.$.new_field
或
$sites.$.energy_consumption
但是我得到了错误
FieldPath field names may not start with '$'
相关:
In MongoDB how do you use $set to update a nested value/embedded document?
使用$addFields
db.collection.update({},
[
{
"$addFields": {
"sites": {
$map: {
input: "$sites",
as: "s",
in: {
name: "$$s.name",
energy_consumption: "$$s.energy_consumption",
new_field: {
$map: {
input: "$sites",
as: "value",
in: "$$value.energy_consumption"
}
}
}
}
}
}
}
])
我发现以下设置完整 sites
而不是仅使用点符号指定新字段的丑陋解决方法:
a) 基于javascript函数
set_stage = {
"$set": {
"sites": {
"$function": {
"body": "function(sites) {return sites.map(site => {site.new_field = site.energy_consumption_in_mwh; return site})}",
"args": ["$sites"],
"lang": "js"
}
}
}
}
b) 基于地图和mergeObjects
set_stage = {
"$set": {
"sites": {
"$map": {
"input": "$sites",
"in": {
"$mergeObjects": ["$$this", {
"new_field": "$$this.energy_consumption_in_mwh"
}]
}
}
}
}
}
如果点运算符表达式有某种 $$this 上下文,允许更优雅的解决方案,请告诉我。
如果通过选择该字段是数组的成员,您将选择所有这些字段。
{ar :[{"a" : 1}, {"a" : 2}]}
"$ar.a" = [1 ,2]
此外,您不能将更新运算符与聚合混合使用,您不能使用诸如
$sites.$.energy_consumption
,如果要进行聚合,则必须使用聚合运算符,只有 $match
阶段可以使用查询运算符。
查询
- 与您使用
$setField
的解决方案略有不同
- 我想它会更快,但可能差别不大
- 不用javascript会比较慢
- 这是>=MongoDB5的解,
$setField
是new运算符
aggregate(
[{"$set":
{"sites":
{"$map":
{"input":"$sites",
"in":
{"$setField":
{"field":"new_field",
"input":"$$this",
"value":"$$this.energy_consumption"}}}}}}]
)