Mongodb updateMany属性更改为其他属性的确切值

时间:2019-12-09 17:06:09

标签: mongodb

我有一些文档,它们代表用户的入职数据存储为嵌套对象:

{
    "_id" : ObjectId("5c7eb0132e6f793bcc7f4bf7"),
    "userName" : "sample_user_name",
    "onBoarding" : {
        "completed" : ISODate("2019-03-05T17:46:28.803Z"),
        "stepId" : 8,
        "started" : null
    }
}

但是由于存在一个错误,我们错过了入职开始的日期,我想通过运行将“开始”的日期设置为与“完成”相同的更新操作来“检索”此信息。我有一个查询,例如:

db.getCollection('user').updateMany(
{ 
  $and: [
      {"onBoarding.started": {$exists: false}},
      {"onBoarding.completed": {$exists: true}}
]}, 
{
  $set: { "onBoarding.started": "$onBoarding.completed" }
})

但是,这实际上将“开始”设置为“ $ onBoarding”(作为字符串)。

{
    "_id" : ObjectId("5c7eb0132e6f793bcc7f4bf7"),
    "userName" : "sample_user_name",
    "onBoarding" : {
        "completed" : ISODate("2019-03-05T17:46:28.803Z"),
        "stepId" : 8,
        "started" : "$onBoarding"
    }
}

我应该如何为mongo编写它以从“ onBoarding.completed”中获取一个值并将该值复制到“ onBoarding.started”中? 预期结果文档应如下所示:

{
    "_id" : ObjectId("5c7eb0132e6f793bcc7f4bf7"),
    "userName" : "sample_user_name",
    "onBoarding" : {
        "completed" : ISODate("2019-03-05T17:46:28.803Z"),
        "stepId" : 8,
        "started" : ISODate("2019-03-05T17:46:28.803Z")
    }
}

2 个答案:

答案 0 :(得分:1)

exists运算符检查字段的存在。如果字段的值为null,查询仍将返回true(因为该字段仍然存在,因此只有其值为null)。

以下查询与此输入文档的行为有所不同:{ _id: 1, fld1: 123, fld2: null }

  • db.test.find( { fld2: { exists: false } } )返回false
  • db.test.find( { fld2: null } } )返回true

回到有问题的数据-以下查询/脚本将更新具有以下条件的所有文档:(“ onBoarding.started”为null 存在) (“ onBoarding.completed”字段存在并且不是null)。

db.test.find( { $and: [ { $or: [ { "onBoarding.started": null },  { "onBoarding.started": { $exists: false } } ] },  { $and: [ { "onBoarding.completed": { $exists: true } }, { "onBoarding.completed": { $ne: null } } ] } ] } ).forEach( doc => db.test.updateOne( { _id: doc._id }, { $set: { "onBoarding.started" : doc.onBoarding.completed } } ) )



使用 MongoDB 4.2版,可以按以下方式运行相同的更新。请注意, update 使用聚合阶段(请参见update上的文档资料)。

db.test.updateMany(
  { $and: [ { $or: [ { "onBoarding.started": null },  { "onBoarding.started": { $exists: false } } ] },  { $and: [ { "onBoarding.completed": { $exists: true } }, { "onBoarding.completed": { $ne: null } } ] } ] },
  [
    { $addFields: 
        { "onBoarding.started" : "$onBoarding.completed" } 
    }
  ]
)

答案 1 :(得分:0)

您需要使用聚合管道才能使用另一个字段的值:

db.user.updateMany(
   { <your query selector > },
   [
      { $set: { onBoarding.started: "$onBoarding.completed" } },
   ]
)

请注意,这里的$ set指的是聚合管道阶段,而不是更新操作符$ set:https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/index.html#update-with-aggregation-pipeline