MongoDB Collection更新:使用默认值初始化文档 [英] MongoDB Collection update: initialize a document with default values

查看:327
本文介绍了MongoDB Collection更新:使用默认值初始化文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用MongoDB处理时间序列.社区采用的常见解决方案是使用子文档以不同的粒度级别存储信息(请参阅

I am trying to deal with time series using MongoDB. The common solution adopted by community is to use subdocuments to store information at different level of granularity (see Schema Design for Time Series Data in MongoDB).

例如,看看以下文档:

{
  timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"),
  type: "memory_used",
  values: [
    999999,   // 1 second
    …
    1000000,  // nth second
    1500000,  // n+1th second
    … 
    2000000   // 60th
  ]
}

该文档以分钟信息编制索引,并包含一个子文档,该子文档存储每秒的更多详细信息.

The document is indexed by minute information and contains a subdocument which store more detailed information for each second.

到目前为止,一切都很好.这种方法需要进行优化才能正常工作:

So far so good. This kind of approach requires an optimization to work properly:

另一项优化[..]是为即将到来的时间段预分配所有文档;这绝不会导致现有文档在磁盘上增长或移动.

Another optimization [..] is preallocating all documents for the upcoming time period; This never causes an existing document to grow or be moved on disk.

要实现上述优化,可以在update方法上使用$setOnInsert属性.

To implement the above optimization one could use the $setOnInsert property on the update method.

db.getCollection('aCollection').update(
    {
      timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"),
      type: "memory_used"
    },
    {
      $setOnInsert: { values: {'0': 0, '1': 0, '2': 0}},
      $inc: {"values.30": 1}
    },
    { upsert: true }
)

问题在于,不可能在两个不同的操作中的同一更新中使用同一字段.上面的更新指令产生以下错误:

The problem is that it is not possible to use the same field in the same update in two different operation. The above update istruction generates the following error:

Cannot update 'values' and 'values.30' at the same time

此问题已在问题上得到跟踪.

This problem is tracked on this issue.

我的问题是:有什么解决方法吗?我的前缀是我不能使用任何预分配空文档的批处理,因为我不知道索引字段 a的值优先级(在上面的示例中,字段type的值.

My question is: is there any workaround? I prefix that I can't use any batch that preallocates empty documents, because I can't know the value of the indexed fields a priori (in the above example, the values of the field type.

谢谢.

推荐答案

我和我的同事们找到了一种解决方法.我们可以将其称为"三步初始化".

Me and my colleagues found a workaround. We can call it three step initialization.

请记住,MongoDB保证单个文档上操作的原子性.考虑到这一事实,我们可以通过以下方式进行操作:

Remember that MongoDB guarantees the atomicity of operations on a single document. With this fact in mind we can operate in the following way:

  1. 尝试更新文档,在指定的时间块正确增加计数器.不要执行任何更新操作,而只是执行老式的更新操作.请记住,执行更新语句将返回写入的文档数.如果写入的文档数大于零,则说明已完成.
  2. 如果更新写入的文档数为零,则表示该集合中尚不存在要更新的相对文档.尝试为指定的标签插入整个文档.将所有计数器(字段值)设置为零.同样,执行insert语句还可以返回写入的文档数.如果返回零或引发异常,请放心:这意味着其他某个进程已经为相同的标签插入了文档.
  3. 再次执行与上述相同的更新.

该代码应类似于以下代码片段.

The code should looks like something similar to the following code snippet.

// Firt of all, try the update
var result = db.test.update(
  {timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), type: "memory_used"},
  {$inc: {"values.39": 1}},
  {upsert: false}
);
// If the update do not succeed, then try to insert the document
if (result.nModified === 0) {
  try {
    db.test.insert(/* Put here the whole document */);
  } catch (err) {
    console.log(err);
  }
  // Here we are sure that the document exists.
  // Retry to execute the update statement
  db.test.update(/* Same update as above */);
}

如果前提条件成立,以上过程将起作用:_id值应从文档中的其他字段得出.在我们的示例中,_id值将为'2013-10-10T23:06:00.000Z-memory_used.仅使用此技术,点2处的插入将正确地失败.

The above procedure works if a precondition holds: _id value should be derived from other fields in the document. In our example, _id value would be '2013-10-10T23:06:00.000Z-memory_used. Only using this technique, the insert at point 2. will properly fail.

这篇关于MongoDB Collection更新:使用默认值初始化文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆