我的db模型看起来像这样
"clientId":"123456"
"devices" :
[{
"deviceId" : "123",
"deviceType" : "ios",
"notification" : true,
}
{
"deviceId" : "321",
"deviceType" : "android",
"notification" : true,
}
]
我传递给我的DB方法的c#模型有ClientId,DeviceId,DeviceType和通知。请注意,它没有设备阵列
我试图实现的行为
(工作)如果ClientId尚未在数据库中,请在db中使用传递的值创建一条新记录(devices数组将包含一个元素)
如果已在数据库中找到ClientId,请根据以下规则更新记录:
2.1如果设备数组不包含DeviceId,则使用传递的值向数组添加新元素
2.2如果设备阵列已包含DeviceId,则更新元素的deviceType和通知。
我正在使用c#。任何帮助赞赏
示例:给定上述数据库状态,通过传递clientId:123456,deviceId 321 deviceType" kindle",notification" false"数据库将更改为
"clientId":"123456"
"devices" :
[{
"deviceId" : "123",
"deviceType" : "ios",
"notification" : true,
}
{
"deviceId" : "321",
"deviceType" : "kindle",
"notification" : false,
}
]
答案 0 :(得分:6)
这并不像你想象的那么简单,实际上有趣的是你已经把你的分析分成了三个部分。因为,猜猜怎么着?这正是您必须所做的。让我们考虑一下步骤:
db.collection.update(
{
"clientId":"123456"
},
{
"$setOnInsert": {
"clientId": "123456",
"devices": [{
"deviceId": "321",
"deviceType" : "kindle",
"notification" : false
}]
}
},
{ "upsert": true }
)
所以你要做的是插入一个新文档,其中“clientId”目前不存在。这可以作为“upsert”来完成,以避免可能的唯一键冲突,即使没有“唯一”约束,那么这种“upsert”性质可确保您只在未找到时创建“新”文档。此外还有$setOnInsert
,因为您不想要对此时“找到”的文档执行任何操作。
请注意,否尝试匹配数组中的元素。这是因为您可能不想仅仅因为现有文档没有“那个”数组元素而“创建”新文档。这将我们带到下一步。
db.collection.update(
{
"clientId":"123456",
"devices": { "$elemMatch": { "deviceId" : "321" } }
},
{
"$set": {
"devices.$.deviceType" : "kindle",
"devices.$.notification" : false
}
}
)
现在,您希望实际尝试“匹配”“clientId”的文档,执行包含数组中的元素,该元素也与您要查找的“deviceId”相匹配。因此,通过指定要匹配的条件,您可以使用位置$
运算符,以便将字段设置为“匹配”位置。
如上所述,这要么与一个匹配,要么没有,因此更新已完成或未完成。所以这就移到了我们级联的最后一部分:
db.collection.update(
{
"clientId":"123456"
},
{
"$addToset": { "devices": {
"deviceId" : "321",
"deviceType" : "kindle",
"notification" : false
}}
}
)
所以这是重要的最后一个阶段。原因是,如果上述任何一项操作 “创建”或“更新”现有文档,那么$addToSet
在此使用确定就是不要将另一个文档“推”到具有相同“deviceId”但其他不同值的数组。如果这些阶段的一个工作,那么这将看到该元素的所有值已经存在,并且不会再添加另一个。
如果您尝试以不同的顺序执行此操作,在您出现的情况下,阵列中的两个文档具有相同的“deviceId”,但“deviceType”和“”的值不同通知”。所以这就是最后的原因。
所以不幸的是,没有简单的方法可以将这些结合起来作为一个操作。操作符根本不存在,因此可以在单个语句中完成,因此您必须执行三次更新操作才能执行您想要的操作。同样如上所述,这些更新的订单是重要,以便您获得所需的结果。
虽然目前的“生产”版本中尚不存在这种情况,但即将发布的版本(编写时为2.6及更高版本)确实可以通过"batch"的新语法update这些请求:
db.runCommand(
"update": "collection",
"updates": [
{
"q": { "clientId":"123456" },
"u": {
"$setOnInsert": {
"clientId": "123456",
"devices": [{
"deviceId": "321",
"deviceType" : "kindle",
"notification" : false
}]
},
"upsert": true
},
{
"q": {
"clientId":"123456",
"devices": { "$elemMatch": { "deviceId" : "321" } }
},
"u": {
"$set": {
"devices.$.deviceType" : "kindle",
"devices.$.notification" : false
}
}
},
{
"q": { "clientId":"123456" },
"u": {
"$addToset": { "devices": {
"deviceId" : "321",
"deviceType" : "kindle",
"notification" : false
}}
}
}
]
)
所以虽然仍然基本上是三个操作,但至少你只需要通过电线发送
答案 1 :(得分:0)
您正在寻找典型的位置操作员案例:
db.coll.update
(
{
"clientId":"123456","devices.deviceId":"321"
},
{
$set:
{
"devices.$.deviceType":"kindle","devices.$.notification":"false"
}
}
)
您需要更新数组内匹配的元素,$为您执行此操作,因此您可以在数组中找到包含特定元素的文档,并且#34;记住"使用位置运算符$匹配哪一个来更新它。