Arrays 为什么这个db.eval->;array.push是否对某些记录执行两次?

Arrays 为什么这个db.eval->;array.push是否对某些记录执行两次?,arrays,mongodb,Arrays,Mongodb,我想在与简单选择器匹配的记录中向数组添加一个对象元素,因此我运行了以下查询: db.eval(function() { db.companies.find({exchange: 'OTC'}).forEach(function(c) { c.links.push({ url: 'http://www.otcmarkets.com/stock/' + c.symbol + '/profile', text: 'OTCMa

我想在与简单选择器匹配的记录中向数组添加一个对象元素,因此我运行了以下查询:

db.eval(function() { 
    db.companies.find({exchange: 'OTC'}).forEach(function(c) {
          c.links.push({
            url: 'http://www.otcmarkets.com/stock/' + c.symbol + '/profile',
            text: 'OTCMarkets.com'
          });
          db.companies.save(c);
    });
});
在与选择器匹配的大约10000条记录中,大约1100条记录的两个链接被推到了数组的末尾。什么可能导致这种情况?大约1000个有空的
链接
数组,但大约100个有一个或多个元素在数组中:

{
"_id": "...",
...
"exchange": "OTC",
"links": [
    {
        "text": "Website",
        "url": "..."
    },
    {
        "text": "OTCMarkets.com",
        "url": "http://www.otcmarkets.com/stock/GREN/profile"
    },
    {
        "text": "OTCMarkets.com",
        "url": "http://www.otcmarkets.com/stock/GREN/profile"
    }
],
"name": "GreenSmart Corp.",
...
}
大多数其他记录只正确地推送了一个数组元素:

{
"_id": "6WiXSoefPtqJdmzxa",
...
"exchange": "OTC",
...
"links": [
    {
        "text": "Website",
        "url": "..."
    },
    {
        "text": "Financial Information",
        "url": "..."
    },
    {
        "text": "Executives",
        "url": "..."
    },
    {
        "text": "OTCMarkets.com",
        "url": "http://www.otcmarkets.com/stock/SFEF/profile"
    }
],
"name": "Santa Fe Financial Corp.",
...
}
为了简洁起见,我省略了记录中的字段,但我无法理解为什么有些人会将OTCMarkets链接元素推一次,而其他人推两次

Mongo 2.6.3.

由于您的分类:

 db.companies.find({exchange: 'OTC'})
这是naural排序,由于您的更新很可能不适用于这1100个文档,因此会导致一些文档移动到MongoDB内部链接列表的末尾,这是默认的排序顺序;因此,您将获得重复的文档

使用类似于_id或其他东西的东西对查询进行排序。由于您的排序:

 db.companies.find({exchange: 'OTC'})
这是naural排序,由于您的更新很可能不适用于这1100个文档,因此会导致一些文档移动到MongoDB内部链接列表的末尾,这是默认的排序顺序;因此,您将获得重复的文档


用“id”之类的东西对你的问题进行排序。

你的问题被劫持了,只是为了进行一些旁白讨论,但我想在回答中纠正我的错误,以免误导你或其他人。
$isolated
操作符不会帮助您,因为是您自己的更新导致文档移动(因为它们会改变大小),然后通过集合扫描再次被发现。使用Sammaye建议的排序

另外,请不要使用
$isolated
,除非您确实确定需要一个独立的更新;另外,不要忘记,
$isolated
更新在隔离时不是原子的


最后,请不要使用db.eval。在its中讨论了它的一系列限制,它将被聚合框架和对数据库执行>1调用所取代。

您的问题被劫持了一小部分旁白讨论,但我想在回答中纠正我的错误,以免误导您或其他人。
$isolated
操作符不会帮助您,因为是您自己的更新导致文档移动(因为它们会改变大小),然后通过集合扫描再次被发现。使用Sammaye建议的排序

另外,请不要使用
$isolated
,除非您确实确定需要一个独立的更新;另外,不要忘记,
$isolated
更新在隔离时不是原子的


最后,请不要使用db.eval。its中讨论了它的一系列限制,它将被聚合框架取代,并对数据库进行>1次调用。

多奇怪啊。而且完全违反直觉,违反了最小意外原则。@DanDascalescu这是一个奇怪的现象,但当您对文档使用连续空间分配时,当它超出其空间时,它必须移动到新的空间,并且需要记录更改,由于没有排序,所以假定您希望按该顺序返回是的,但我希望不要假定您希望10%的记录被处理两次。值得一提的是,这种现象是存在的,并且有一个
$isolated
操作符(记录在该链接中)这将防止在更新过程中让步,并应防止看到同一文档两次。但是,请注意,这意味着更新将在其持续时间内保持数据库级锁(在2.6中)。@wdberkeley这是否已分片隔离?多么奇怪。而且完全违反直觉,违反了最小意外原则。@DanDascalescu这是一个奇怪的现象,但当您对文档使用连续空间分配时,当它超出其空间时,它必须移动到新的空间,并且需要记录更改,由于没有排序,所以假定您希望按该顺序返回是的,但我希望不要假定您希望10%的记录被处理两次。值得一提的是,这种现象是存在的,并且有一个
$isolated
操作符(记录在该链接中)这将防止在更新过程中让步,并应防止看到同一文档两次。但是,请注意,这意味着更新将持有数据库级锁(在2.6中)在它的持续时间内。@wdberkeley有切分隔离吗?应该使用什么代替
db.eval
来迭代所有记录并根据其中的字段更新每个记录?应该使用什么代替
db.eval
来迭代所有记录并根据其中的字段更新每个记录?