在MongoDB FindAndModify中使用现有文档数据和新信息

时间:2014-06-11 00:43:20

标签: mongodb findandmodify

创建订单时,文档具有以下架构:

{order:1,startTime:1402442830110}

订单完成后,会处理db.collection.findAndModify()操作以设置endTime,从而产生如下文档:

{order:1,startTime:1402442830000,endTime:1402442930000}

在同一过程中,我需要设置顺序duration,通过减去两次来计算:doc.endTime-doc.startTime

是否有操作员或程序可以帮助您在一次操作中执行此操作?或者我是否必须执行两个FindAndModify操作,一个用于设置返回新文档的新数据,另一个用于设置duration字段?

3 个答案:

答案 0 :(得分:2)

从我理解的内容,转换为SQL,你想做这样的事情

UPDATE [Order] SET
    EndTime = GETDATE(),
    Duration = GETDATE() - StartTime
WHERE OrderID = ''

不幸的是,MongoDB尚不支持。但是,您仍然可以通过2次更新来完成。第一个不一定是findAndModifyfindOne就足够了。

var startTime = db.order.findOne({order: 1}).startTime;
var endTime = new Date();
db.order.findAndModify({
    query: {order: 1},
    update: {$set: {endTime: endTime, duration: endTime - startTime}}
});

实际上,我不认为此处的findAndModify会为您带来除纯update之外的任何优势,除非您想要阻止同一订单多次更新。在这种情况下,最好改变这样的条件:

var startTime = db.order.findOne({order: 1}).startTime;
var endTime = new Date();
db.order.findAndModify({
    query: {order: 1, endTime: {$exists: false}},
    update: {$set: {endTime: endTime, duration: endTime - startTime}}
});

在我看来,你应该有一些东西来控制订单的状态,比如订购/付款/取消......要锁定状态的订单会比{endTime: {$exists: false}}好得多。

答案 1 :(得分:0)

您可以使用聚合框架执行此操作。以下是示例代码:

db.col.aggregate(
[
    {$match:{order:1}},
    {$project:{order:1, startTime:1,endTime:{$add:[new Date().getTime()]}}},
    {$project:{order:1,startTime:1,endTime:1,duration:{$subtract:["$endTime","$startTime"]}}}
])

这是给定管道的执行方式:

  1. $ match将选择符合条件order = 1
  2. 的订单
  3. 第一个$项目将添加" endTime"所选订单的财产
  4. 第二个$ project将通过从endTime
  5. 中减去startTime将持续时间字段添加到所选订单

答案 2 :(得分:0)

您的代码的第一个问题是:您使用两个不同的单元(即普通的javascript和MongoDB)来为文档添加时间戳。不是使用两个不同的程序是错误的,但在这种情况下,它们返回时间的格式不一样!

您可以让MongoDB单独完成所有操作,也可以让Nodejs完成。因为MongoDB不允许在其更新查询中执行数学运算,因此最好的方法是通过javascript本身(或者用于与MongoDB交互的任何内容)来实现这一点。只需将doc提取到orderSave(),获取此订单的endTime,计算duration并运行:

db.collection.update (
                      {'order' : {$eq: valueOfOrderToUpdate}},
                      {
                         $set : {'endTime': calculatedEndTimeValue},
                         $set : {'duration' : calculatedDuration}
                      },
                      {upsert : true}
);