Mongo 根据数组中子文档的值进行迁移以设置值
Mongo make migration to set value based on value of a subdocument in array
我有这样的文档结构:
_id: "xx"
statuses: [{
status: "pending",
timestamp: "1 january 10 pm",
}, {
status: "accepted",
timestamp: "2 january 2 am",
}]
现在我想在根结构中添加接受的时间戳。
_id: "xx"
statuses: [{
status: "pending",
timestamp: "1 january 10 pm",
}, {
status: "accepted",
timestamp: "2 january 2 am",
}]
last_accepted_at: "2 january 2 am"
我知道如何根据另一个根字段设置值,但不知道如何根据我必须过滤的数组项设置值。
我试过了:
db.task.findOneAndUpdate( { last_accepted_at: { $exists: false } }, { $set: { "last_accepted_at": "statuses.$[element].timestamp" }}, { arrayFilters: [ { "element.status": "accepted" } ] }, )
有错误
uncaught exception: Error: findAndModifyFailed failed: {
"ok" : 0,
"errmsg" : "The array filter for identifier 'element' was not used in the update { $set: { last_accepted_at: \"statuses.$[element].timestamp\" } }",
"code" : 9,
"codeName" : "FailedToParse"
} :
我也试过:
db.task.findOneAndUpdate( { last_accepted_at: { $exists: false } }, { $set: { "last_accepted_at": "statuses.$[element].timestamp" }}, { arrayFilters: [ { "element.$.status": "accepted" } ] }, )
uncaught exception: Error: findAndModifyFailed failed: {
"ok" : 0,
"errmsg" : "The array filter for identifier 'element' was not used in the update { $set: { last_accepted_at: \"statuses.$[element].timestamp\" } }",
"code" : 9,
"codeName" : "FailedToParse"
} :
如何实现?我也想使用 updateMany 因为它是一个迁移文件来更新所有旧数据。
谢谢
"The array filter for identifier 'element' was not used in the update { $set: { last_accepted_at: "statuses.$[element].timestamp" } }",
错误提示您不能将 arrayFilters 用作任何字段的值,您只能将其用作键的一部分,有关详细信息,请参阅 $[<identifier>]
、
其次,普通更新查询不允许内部字段作为另一个字段的值,需要使用update with aggregation pipeline从MongoDB 4.2开始,
$filter
迭代 statuses
数组的循环并获得“已接受”状态结果
$arrayElemAt
从上面过滤的结果中获取第一个元素
$set
从上面的 arrayElemAt 操作 从 return 对象得到 timestamp
db.task.updateMany({
last_accepted_at: { $exists: false },
"statuses.status": "accepted"
},
[
{
$set: {
last_accepted_at: {
$arrayElemAt: [
{
$filter: {
input: "$statuses",
cond: { $eq: ["$$this.status", "accepted"] }
}
},
0
]
}
}
},
{
$set: { last_accepted_at: "$last_accepted_at.timestamp" }
}
])
我有这样的文档结构:
_id: "xx"
statuses: [{
status: "pending",
timestamp: "1 january 10 pm",
}, {
status: "accepted",
timestamp: "2 january 2 am",
}]
现在我想在根结构中添加接受的时间戳。
_id: "xx"
statuses: [{
status: "pending",
timestamp: "1 january 10 pm",
}, {
status: "accepted",
timestamp: "2 january 2 am",
}]
last_accepted_at: "2 january 2 am"
我知道如何根据另一个根字段设置值,但不知道如何根据我必须过滤的数组项设置值。
我试过了:
db.task.findOneAndUpdate( { last_accepted_at: { $exists: false } }, { $set: { "last_accepted_at": "statuses.$[element].timestamp" }}, { arrayFilters: [ { "element.status": "accepted" } ] }, )
有错误
uncaught exception: Error: findAndModifyFailed failed: {
"ok" : 0,
"errmsg" : "The array filter for identifier 'element' was not used in the update { $set: { last_accepted_at: \"statuses.$[element].timestamp\" } }",
"code" : 9,
"codeName" : "FailedToParse"
} :
我也试过:
db.task.findOneAndUpdate( { last_accepted_at: { $exists: false } }, { $set: { "last_accepted_at": "statuses.$[element].timestamp" }}, { arrayFilters: [ { "element.$.status": "accepted" } ] }, )
uncaught exception: Error: findAndModifyFailed failed: {
"ok" : 0,
"errmsg" : "The array filter for identifier 'element' was not used in the update { $set: { last_accepted_at: \"statuses.$[element].timestamp\" } }",
"code" : 9,
"codeName" : "FailedToParse"
} :
如何实现?我也想使用 updateMany 因为它是一个迁移文件来更新所有旧数据。 谢谢
"The array filter for identifier 'element' was not used in the update { $set: { last_accepted_at: "statuses.$[element].timestamp" } }",
错误提示您不能将 arrayFilters 用作任何字段的值,您只能将其用作键的一部分,有关详细信息,请参阅 $[<identifier>]
、
其次,普通更新查询不允许内部字段作为另一个字段的值,需要使用update with aggregation pipeline从MongoDB 4.2开始,
$filter
迭代statuses
数组的循环并获得“已接受”状态结果$arrayElemAt
从上面过滤的结果中获取第一个元素$set
从上面的 arrayElemAt 操作 从 return 对象得到
timestamp
db.task.updateMany({
last_accepted_at: { $exists: false },
"statuses.status": "accepted"
},
[
{
$set: {
last_accepted_at: {
$arrayElemAt: [
{
$filter: {
input: "$statuses",
cond: { $eq: ["$$this.status", "accepted"] }
}
},
0
]
}
}
},
{
$set: { last_accepted_at: "$last_accepted_at.timestamp" }
}
])