英文:
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
问题
我有一个包含两个并行数组的文档格式,分别是playerColors
和players
。players
数组中的每个玩家对象都在playerColors
数组中具有与之相关联的颜色整数,索引相同。我该如何构建一个查询,通过他们的id
同时删除玩家并从playerColors
数组中删除他们关联的颜色整数?
我的最初想法是使用一个查找查询来定位玩家的索引,然后使用一个更新查询来通过索引删除playerColors
和players
数组中对应的条目。然而,如果存在其他可能修改这些数组的更新,这是否会引入竞态条件呢?
英文:
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
中删除的元素的匹配索引。然后,我们根据情况修改array1
和array2
:如果matchingIndex
为负数,则保持数组不变,否则,我们通过拼接和连接它们生成一个新数组。您可以根据自己的用例修改示例。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论