mongoDB upsert在数组上

时间:2014-03-26 15:01:17

标签: c# arrays mongodb mongodb-query

我的db模型看起来像这样

"clientId":"123456"
"devices" : 
[{
      "deviceId" : "123",
      "deviceType" : "ios",
      "notification" : true,
  }
  {
      "deviceId" : "321",
      "deviceType" : "android",
      "notification" : true,

  }
 ]

我传递给我的DB方法的c#模型有ClientId,DeviceId,DeviceType和通知。请注意,它没有设备阵列

我试图实现的行为

  1. (工作)如果ClientId尚未在数据库中,请在db中使用传递的值创建一条新记录(devices数组将包含一个元素)

  2. 如果已在数据库中找到ClientId,请根据以下规则更新记录:

    2.1如果设备数组不包含DeviceId,则使用传递的值向数组添加新元素

    2.2如果设备阵列已包含DeviceId,则更新元素的deviceType和通知。

  3. 我正在使用c#。任何帮助赞赏

    示例:给定上述数据库状态,通过传递clientId:123456,deviceId 321 deviceType" kindle",notification" false"数据库将更改为

    "clientId":"123456"
    "devices" : 
    [{
          "deviceId" : "123",
          "deviceType" : "ios",
          "notification" : true,
      }
      {
          "deviceId" : "321",
          "deviceType" : "kindle",
          "notification" : false,
    
      }
     ]
    

2 个答案:

答案 0 :(得分:6)

这并不像你想象的那么简单,实际上有趣的是你已经把你的分析分成了三个部分。因为,猜猜怎么着?这正是您必须所做的。让我们考虑一下步骤:

1。如果文档不存在,则插入文档

db.collection.update(
    { 
        "clientId":"123456"
    },
    {
        "$setOnInsert": {
            "clientId": "123456",
            "devices": [{
                "deviceId": "321",
                "deviceType" : "kindle",
                "notification" : false
            }]
        }
    },
    { "upsert": true }
)

所以你要做的是插入一个新文档,其中“clientId”目前不存在。这可以作为“upsert”来完成,以避免可能的唯一键冲突,即使没有“唯一”约束,那么这种“upsert”性质可确保您只在未找到时创建“新”文档。此外还有$setOnInsert,因为您想要对此时“找到”的文档执行任何操作。

请注意,尝试匹配数组中的元素。这是因为您可能不想仅仅因为现有文档没有“那个”数组元素而“创建”新文档。这将我们带到下一步。

2。更新文档存在的内容

db.collection.update(
    { 
        "clientId":"123456",
        "devices": { "$elemMatch": { "deviceId" : "321" } }
    },
    {
        "$set": {
            "devices.$.deviceType" : "kindle",
            "devices.$.notification" : false
        }
    }
)

现在,您希望实际尝试“匹配”“clientId”的文档,执行包含数组中的元素,该元素也与您要查找的“deviceId”相匹配。因此,通过指定要匹配的条件,您可以使用位置$运算符,以便将字段设置为“匹配”位置。

如上所述,这要么与一个匹配,要么没有,因此更新已完成或未完成。所以这就移到了我们级联的最后一部分:

3。添加不存在的数组元素

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;记住"使用位置运算符$匹配哪一个来更新它。