mongodb - MongoDB 数据建模:如何比较子文档字段和根文档字段?
问题描述
在 MongoDB 集合中,我正在尝试对一些具有一些“输入”的硬件“设备”进行建模,并具有以下约束:一次应激活单个输入。
这是我用来模拟设备及其输入的(简化的)文档:
{
"_id" : "device1",
"inputs" : [
{
"connectedTo" : "device3",
"index" : 2
},
{
"connectedTo" : null,
"index" : 3
},
{
"connectedTo" : null,
"index" : 4
}
]
}
现在我正在尝试实现“活动”输入功能。我看到了两种方法:
- 在存储活动输入索引的根文档中添加一个“activeInput”字段
- 在每个输入子文档上添加一个“活动”标志(布尔)字段,只有一个将活动标志设置为 true 的输入
但是,我在使用这两种方法编写 MongoDB 更新时遇到了一些问题:
使用方法 1:我找不到查询/更新活动输入子文档的方法。这是我尝试的过滤器:
{"inputs.index": {"$eq": "$activeInput"}}
{"$where": "this.inputs.index==this.activeInput"}
{"$expr": {"$eq": ["$inputs.index", "$activeInput"]}}
似乎我们无法比较子文档的字段,或者我找不到如何做到这一点。
使用方法 2:我找不到一种方法来自动更新活动标志,以便一次只有一个输入处于活动状态。对于具有给定索引值的子文档,我需要将活动标志设置为 true,而对于其他子文档,我需要将其设置为 false,但我不知道如何自动执行此操作。
也许我还没有找到正确的方法来模拟“主动”输入功能,所以有人可以帮忙吗?
解决方案
采用方法 1
您可以使用更新管道解决此问题,但这会非常复杂:
- 计算一个
newActiveInput
包含未来新活动输入的新字段 - 更新
activeInput
和inputs
字段 - 删除
newActiveInput
字段
db.getCollection('test').update(
{"_id" : "device1"},
[
{
"$addFields": {
"newActiveInput": {
"$arrayElemAt": [
{
"$map": {
"input": {
"$filter": {
"input": "$inputs",
"cond": {
"$and": [
{"$ne": ["$$this.index", "$activeInput"]},
{"$eq": ["$$this.connectedTo", null]}
]
}
}
},
"as": "input",
"in": "$$input.index"
},
}, 0
]
}
}
},
{
"$set": {
"activeInput": "$newActiveInput",
"inputs": {
"$concatArrays": [
{
"$filter": {
"input": "$inputs",
"cond": {"$lt": ["$$this.index", "$newActiveInput"]}
}
},
[{"connectedTo": "newDevice", "index": "$newActiveInput"}],
{
"$filter": {
"input": "$inputs",
"cond": {"$gt": ["$$this.index", "$newActiveInput"]}
}
},
]
}
}
},
{
"$unset": "newActiveInput"
}
]
)
采用方法 2
以下更新将设置active=true
ifconnectedTo == "device4"
和active=false
else:
db.getCollection('test').update(
{"_id" : "device1"},
[
{
"$set": {
"inputs": {
"$map": {
"input": "$inputs",
"as": "input",
"in": {
"$mergeObjects": [
"$$input",
{
"active": { "$cond": [ {"$eq": ["$$input.connectedTo", "device4"]}, true, false ] }
}
]
}
}
}
}
}
]
)
另一种解决方案是使用arrayFilters
标识要更新的子文档,然后$bit
更新以反转当前active
值。由于$bit
仅适用于整数,因此您需要表示active
为整数:
db.getCollection('test').update(
{
"_id" : "device1"
},
{
"$bit": {"inputs.$[input].active" : {"xor": NumberInt(1)}}
},
{
"multi": true,
"arrayFilters": [
{
"$or": [
{"input.active": NumberInt(1)},
{"input.connectedTo": "device5"},
]
}
]
}
)
推荐阅读
- spring-test - 使用 spring 和 pact 进行 CDC 测试时出现“没有找到匹配方法的测试”错误
- django - SQL到django ORM
- google-apps-script - 如何使此模板代码在工作表应用程序中工作
- c# - 仅当它是逗号时,如何从字符串中删除最后一个字符?
- bash - 使用 sed 返回自定义退出代码
- swift - UIButton 文本未显示
- nativescript - Brother Printer SDK 无法打印标签 ERROR_WRONG_LABEL_ IOS
- c++ - 错误 C2447 '{':缺少函数头(旧式正式列表?)
- c# - .Net Core Linux 不支持 SecurityIdentifier?
- google-chrome - chrome浏览器中的PDF图像损坏