在MongoDB中解决bug#1243的最佳方法(使用位置运算符更新数组中的所有项)

时间:2014-03-15 07:06:10

标签: arrays mongodb

我正在编写一个数据库层,其中1:n记录缓存在_children字段中。 所以,如果你有人:

{   
  id: 1,
  name: 'Tony',
  surname: 'Mobily',
  _children: {
    addresses: [],
  }
},
{
  name: 'Chiara',
  surname: 'Mobily',
  _children: {
    addresses: [],
  }
}

然后在地址中添加记录:

{
  id: 100
  personId: 1,
  street: 'Some street',
  country: 'Australia',
}

{
  id: 101
  personId: 1,
  street: 'Some other street',
  country: 'Australia',
}

正确的记录会在人物中自动更新:

{   
  id: 1,
  name: 'Tony',
  surname: 'Mobily',
  _children: {
    addresses: [
      {
        id: 100
        personId: 1,
        street: 'Some street',
        country: 'Australia',
      },

      {
        id: 101
        personId: 1,
        street: 'Some other street',
        country: 'Australia',
      }

    ],
  }
},

我的图层还存储所有文本字段的UPPERCASE版本,并自动运行不区分大小写的搜索等。它还处理"查找"字段,自动填充它们。

当您在地址字段上进行批量更新时,它还会在" parent"上运行更新。字段,以便一切都同步。一切都很美妙。

除非您尝试对地址表进行MASS更新。

例如:

addresses.update( { country: 'Australia' }, { street: 'Something else' }, { multi: true } )

完成此操作后,我还会为每个"父母"运行查询。 table(在这种情况下,people)这样:

people.update( { _children.country: 'Australia'}, { '_children.addresses.$.street': 'Something else' }, { multi: true } )

请注意" new"查询会自动解决。

但是,由于bug https://jira.mongodb.org/browse/SERVER-1243,我基本上搞砸了。

(注意插入总是一个操作,意味着一个简单的$ push(没有问题),而删除是一个需要$ pull on _children的操作($ pull接受一个过滤器来处理数组。所以,也没有问题。。唯一的问题是只有大规模更新。)

现在:

  • 我无法加载完整的文档并手动更改所有条目有以下几个原因:(1)性能:我需要对每个匹配的记录运行更新,它可能是100万; (2)它实际上是不可能的,因为我没有办法重新运行"加载文档上的查询(可能涉及正则表达式等)

  • 我无法重复更新操作,直到我获得ZERO更新(它们都已更改),因为如果更改是匹配,它将永远执行(如果您改变' perth' perth2'并匹配以' p')开头的任何内容。

但是,我真的需要这个功能,而我却无法弄清楚如何去做。

你们有没有想法,除了请求MongoDB的人解决这个问题,这是Mongo阵列更新的又一个弱点?

1 个答案:

答案 0 :(得分:2)

所以考虑到你是"批量更新"并且这可能是一次性操作,您可以考虑使用db.eval()这样:

db.eval(function() {
    db.collection.find({}).forEach(function(doc) {
        doc._children.forEach(function(item) {
            item.ucCountry = item.country.toUpperCase;
        });
        db.collection.update(
            { "_id": doc._id },
            { "$set": { "_children": doc._children } }
        );
    });
})

所以它几乎是标准循环,但这次它在服务器上运行。您甚至可以仅为要更改的数组元素添加$ set操作,以节省更多开销。

请注意阅读文档。您将锁定数据库进行写入,阻止所有其他JavaScript操作,例如" mapReduce"在执行更新期间。但这是最快的方法。