Removing an element from an array in a MongoDB document, and another in a parallel array in the same document, without knowing index ahead of time

huangapple go评论85阅读模式
英文:

Removing an element from an array in a MongoDB document, and another in a parallel array in the same document, without knowing index ahead of time

问题

我有一个包含两个并行数组的文档格式,分别是playerColorsplayersplayers数组中的每个玩家对象都在playerColors数组中具有与之相关联的颜色整数,索引相同。我该如何构建一个查询,通过他们的id同时删除玩家并从playerColors数组中删除他们关联的颜色整数?


我的最初想法是使用一个查找查询来定位玩家的索引,然后使用一个更新查询来通过索引删除playerColorsplayers数组中对应的条目。然而,如果存在其他可能修改这些数组的更新,这是否会引入竞态条件呢?

英文:

I have a document format that consists of two parallel arrays, playerColors and players. Each player object in the players array has an associated color integer in the playerColors array at the same index. How can I construct a query that removes a player by their id and simultaneously removes their associated color integer from the playerColors array?


My initial thought was to use a find query to locate the index of the player, followed by an update query to remove the corresponding entries in both playerColors and players arrays by index. However, would this introduce a race condition if there are other potential updates that modify the arrays?

答案1

得分: 2

首先,您正在使用的数据模型不具有可扩展性。评论中提到的建议是更好的选择。话虽如此,要实现在单个查询中更新两个数组,您可以使用以下更新的管道形式:

db.collection.update({},
[
  {
    $addFields: {
      matchingIndex: {
        "$indexOfArray": [
          "$array2",
          "b"
        ]
      }
    }
  },
  {
    "$addFields": {
      "array1": {
        "$cond": {
          "if": {
            "$lt": [
              "$matchingIndex",
              0
            ]
          },
          "then": "$array1",
          "else": {
            "$concatArrays": [
              {
                $slice: [
                  "$array1",
                  "$matchingIndex"
                ]
              },
              {
                $slice: [
                  "$array1",
                  {
                    $add: [
                      1,
                      "$matchingIndex"
                    ]
                  },
                  {
                    $size: "$array1"
                  }
                ]
              }
            ]
          }
        }
      },
      "array2": {
        "$cond": {
          "if": {
            "$lt": [
              "$matchingIndex",
              0
            ]
          },
          "then": "$array2",
          "else": {
            "$concatArrays": [
              {
                $slice: [
                  "$array2",
                  "$matchingIndex"
                ]
              },
              {
                $slice: [
                  "$array2",
                  {
                    $add: [
                      1,
                      "$matchingIndex"
                    ]
                  },
                  {
                    $size: "$array2"
                  }
                ]
              }
            ]
          }
        }
      }
    }
  },
  {
    "$unset": "matchingIndex"
  }
])

在此查询中,我们首先找到要从array2中删除的元素的匹配索引。然后,我们根据情况修改array1array2:如果matchingIndex为负数,则保持数组不变,否则,我们通过拼接和连接它们生成一个新数组。您可以根据自己的用例修改示例。

Playground链接。

英文:

First of all the data model you are following is not a scalable one. The one suggested in the comments is a better alternative. Having said that, to achieve the update of two arrays in a single query, you can use pipelined form of updates like this:

db.collection.update({},
[
{
$addFields: {
matchingIndex: {
"$indexOfArray": [
"$array2",
"b"
]
}
}
},
{
"$addFields": {
"array1": {
"$cond": {
"if": {
"$lt": [
"$matchingIndex",
0
]
},
"then": "$array1",
"else": {
"$concatArrays": [
{
$slice: [
"$array1",
"$matchingIndex"
]
},
{
$slice: [
"$array1",
{
$add: [
1,
"$matchingIndex"
]
},
{
$size: "$array1"
}
]
}
]
}
}
},
"array2": {
"$cond": {
"if": {
"$lt": [
"$matchingIndex",
0
]
},
"then": "$array2",
"else": {
"$concatArrays": [
{
$slice: [
"$array2",
"$matchingIndex"
]
},
{
$slice: [
"$array2",
{
$add: [
1,
"$matchingIndex"
]
},
{
$size: "$array2"
}
]
}
]
}
}
}
}
},
{
"$unset": "matchingIndex"
}
])

In this query, we first find a matching index, for the element we want to delete from array2. After that, we modify array1 and array2 as follows: if matchingIndex is negative we leave the arrays unchanged, otherwise, we generate a new array by splicing and concatenating them. You can modify the example, as per your use case.

Playground link.

huangapple
  • 本文由 发表于 2023年6月16日 08:31:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76486278.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定