当数组中不存在元素时,$ addToset与$ push的时间复杂度

时间:2012-09-01 07:15:09

标签: mongodb

给定:Connection为Safe = True,因此Update的返回将包含更新信息。

说我有一个类似的文件:

[{'a': [1]}, {'a': [2]}, {'a': [1,2]}]

我发出:

coll.update({}, {'$addToSet': {'a':1}}, multi=True)

结果将是:

{u'connectionId': 28,
 u'err': None,
 u'n': 3,
 u'ok': 1.0,
 u'updatedExisting': True
}

即使来文件已经有了这个价值。为了避免这种情况,我可以发出命令。

coll.update({'a': {'$ne': 1}}, {'$push': {'a':1}}, multi=True)

$ addToSet与$ push的时间复杂度比较是什么?$ / p>

3 个答案:

答案 0 :(得分:16)

看起来 $ addToSet 正在执行与命令相同的操作: $ push with $ ne check 。两者都是O(N)

https://github.com/mongodb/mongo/blob/master/src/mongo/db/ops/update_internal.cpp

如果速度非常重要,那么为什么不使用哈希:

而不是:

{'$addToSet': {'a':1}}
{'$addToSet': {'a':10}}

使用:

{$set: {'a.1': 1}
{$set: {'a.10': 1}

答案 1 :(得分:2)

修改

好的,因为我一直认为你的问题是错误的,事实证明你实际上是在看两个不同的查询并判断它们之间的时间复杂性。

第一个查询是:

coll.update({}, {'$addToSet': {'a':1}}, multi=True)

第二个是:

coll.update({'a': {'$ne': 1}}, {'$push': {'a':1}}, multi=True)

这里首先想到的是问题,没有索引。 $addToSet,作为一个更新修饰符,我不相信它会使用索引,因为您正在进行全表扫描以完成所需的操作。

实际上,您正在查找1中尚未a的所有文档,并期待$push 1数组的值a

因此,在我们进入时间复杂度之前,第二个查询有2点,因为第一个查询:

  • 不使用索引
  • 将是全表扫描
  • 然后对$addToSet
  • 执行完整阵列扫描(没有索引)

所以我几乎已经在这里想到第二个查询是你在任何Big O表示法之前所寻找的东西。

使用大O表示法解释每个查询的时间复杂度存在问题:

  • 我不确定您想要什么样的视角,无论是每个文档还是整个集合。
  • 我不确定索引是这样的。使用索引实际上会在a上创建一个Log算法,但是不使用索引则不会。

然而,第一个查询看起来像:O(n)每个文档,因为:

  • $ addToSet需要迭代每个元素
  • $ addToSet然后需要执行O(1)op来插入集合(如果它不存在)。我应该注意到我不确定O(1)是否被取消(轻读表明我的版本),我已经在这里取消了。

每个集合,没有索引,它将是:O(2n2),因为迭代a的复杂性将随着每个新文档的增加而逐渐增加。

第二个查询,没有索引,看起来像:O(2n2)(每个文档的O(n))我相信,因为$ne与没有索引的$addToSet会有同样的问题。但是对于索引我相信这实际上是O(log n log n)(每个文档的O(log n)),因为它首先会找到所有带有a的文档然后所有文档中都没有1根据b树设置。

因此,基于时间复杂度和开头的注释,我会说查询2更好。

如果我诚实,我不习惯用“大O”符号解释,所以这是实验性的。

希望它有所帮助,

答案 2 :(得分:2)

添加我对addToSet与100k文档批量更新推送之间差异的观察。

进行批量更新时。 addToSet将单独执行。

例如,

bulkInsert.find({x:y}).upsert().update({"$set":{..},"$push":{ "a":"b" } , "$setOnInsert":  {} })

将首先插入并设置文档。然后它执行addToSet查询。

我看到了

之间10k的明显差异
db.collection_name.count() #gives around 40k 

db.collection_name.count({"a":{$in:["b"]}}) # it gives only around 30k

但是用$ push替换$ addToSet。两个count查询都返回了相同的值。

注意:当您不关心数组中的重复条目时。你可以用$ push。