给定: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>
答案 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)每个文档,因为:
每个集合,没有索引,它将是: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。