更新:这个问题的真正目的是找到一个快速的解决方案,我是 MongoDB 的新手,所以我认为如果使用单个查询它会很快,但是,任何快速的解决方案都可以。
基本上我正在寻找解决以下问题的解决方案。由于每个时刻都有数百个这样的操作,因此操作需要快速。
所以我有一个曲线集合,其中包含这样的文档:
{
curveId: 12,
values: [1, 2, 12, 7, ...]
}
假设我想在索引 3 处设置曲线值并导致:
{
curveId: 12,
values: [1, 2, 12, new_value, ...]
}
如果没有匹配的 curveId,则会创建一条新曲线:
{
curveId: 12,
values: [null, null, null, new_value]
}
所以我写了这个更新插入查询:
db.curves.update({
curveId: 12
},{
$set: { "values.3": new_value }
},{
upsert: true
})
当存在匹配的文档时,此方法有效。但是,如果没有匹配,它将创建一个新文档,如下所示:
{
curveId: 12,
values: { '3': new_value }
}
values
不是一个数组,不是我所期望的。
我用谷歌搜索了很长时间但还没有找到解决方案。是否有可能通过一个查询来解决问题?
谢谢你。
当
$concatArrays
数组存在并且是所需的最小大小时,此方法使用 $slice
和 value
。当不满足任何这些条件时,它会使用 $zip
和 $map
来填充缺失值。
更新管道处理这些情况:
[
{ "_id": "curveId exists and is larger", "curveId": 12, "values": [1, 2, 3, 7, 8, 9] },
{ "_id": "curveId exists and values is exact", "curveId": 12, "values": [1, 2, 3, 4] },
{ "_id": "curveId exists but values is short by 1", "curveId": 12, "values": [1, 2, 3] },
{ "_id": "curveId exists but values is short by 2", "curveId": 12, "values": [1, 2] },
{ "_id": "curveId exists but values is empty", "curveId": 12, "values": [] },
{ "_id": "curveId exists but values is null", "curveId": 12, "values": null },
{ "_id": "curveId exists but values does not exist", "curveId": 12 },
{ "_id": "curveId 99 doesn't exist" }
]
使用聚合表达式更新管道:
db.collection.update({ curveId: 12 },
[
{
$set: {
values: {
$let: {
vars: {
// index & new value to set
idx: 3,
new_val: 1000
},
in: {
$cond: {
if: {
$and: [
{ $isArray: "$values" },
{ $lte: [ "$$idx", { $size: "$values" }] } // "lte" is correct here
]
},
then: {
$concatArrays: [
{ $slice: ["$values", "$$idx"] },
["$$new_val"],
{ $slice: ["$values", { $add: ["$$idx", 1] }, { $size: "$values" }] }
]
},
else: {
$let: {
vars: {
vals_nulls: {
$map: {
input: {
$zip: {
inputs: [
{ $ifNull: ["$values", []] },
{ $range: [0, "$$idx"] }
],
useLongestLength: true
}
},
in: { $first: "$$this" }
}
}
},
in: {
$concatArrays: [
{ $slice: ["$$vals_nulls", "$$idx"] },
["$$new_val"],
{ $slice: [
"$$vals_nulls",
{ $add: ["$$idx", 1 ] },
{ $size: "$$vals_nulls" }
]}
]
}
}
}
}
}
}
}
}
}
],
{ upsert: true, multi: true }
)
注:
new_value
和index
只需放在第一个$set -> values -> $let
部分即可
let
参数(如果可用)代替此参数;猫鼬和游乐场没有它multi: true
只需要演示一次执行中的所有更新场景upsert
行为。顺便说一句,
$map
不是一个“慢”操作,至少在这种情况下或在评论中讨论的情况下不是。相比之下,更新的文档检索要慢得多。我将发布一个单独的答案,每次都使用 $map
,就像在 cmghess 的评论中一样,但使用 concat 和 slice。