将较旧的Mongo数据库引用转换为DBRefs

时间:2018-07-13 14:07:59

标签: mongodb

我正在更新仍在Mongo 2.4上运行的某些旧软件。第一步是升级到最新的2.6,然后从那里升级。

运行db.upgradeCheckAllDBs();会给我们带来DollarPrefixedFieldName: $id is not valid for storage.错误,实际上我们有一些带有旧$id, $ref字段的较早记录。我们有许多看起来像这样的收藏集:

{
  "_id" : "1",
  "someRef" : {"$id" : "42",  "$ref" : "someRef"}
},
{
  "_id" : "2",
  "someRef" : DBRef("someRef", "42")
},
{
  "_id" : "3",
  "someRef" : DBRef("someRef", "42")
},
{
  "_id" : "4",
  "someRef" : {"$id" : "42",  "$ref" : "someRef"}
}

我想为此编写脚本,以将较旧的{"$id" : "42", "$ref" : "someRef"}对象转换为DBRef("someRef", "42")对象,但不影响现有的DBRef对象。不幸的是,我无法区分这两种类型的对象。

  • 使用typeof$type只是说它们是对象。
  • 两者都有$id$ref字段。
  • 在我们的groovy控制台中,当您将其中一个旧的拉回去并且将其中一个新的getClass()返回两者的DBRef。

在数以百万计的总记录中,我们有约80,000条这种旧格式的记录。我不愿意强制使用它并修改每条记录是否需要它。

此脚本将执行我需要执行的操作,但是find()基本上将返回集合中的所有记录。

var cursor = db.someCollection.find({"someRef.$id" : {$exists: true}});
while(cursor.hasNext()) {
  var rec = cursor.next();
  db.someCollection.update({"_id": rec._id}, {$set: {"someRef": DBRef(rec.someRef.$ref, rec.someRef.$id)}});
}

我还有另一种想念的方式可以用来只查找违规记录吗?

更新

如已接受的答案中所述,顺序很重要,这一切都与众不同。我们使用的脚本纠正了我们的数据:

var cursor = db.someCollection.find(
  {
    $where: "function() { return this.someRef != null &&
                          Object.keys(this.someRef)[0] == '$id'; }"
  }
);
while(cursor.hasNext()) {
  var rec = cursor.next();
  db.someCollection.update(
    {"_id": rec._id},
    {$set: {"someRef": DBRef(rec.someRef.$ref, rec.someRef.$id)}}
  );
}

我们确实有一个包含大量记录的集合,需要在连接超时的地方进行更正。我们只是再次运行了脚本,它通过了剩余的记录。

可能有更好的方法可以做到这一点。我有兴趣听到更好的方法。目前,此问题已解决。

1 个答案:

答案 0 :(得分:1)

DBRef是客户端的东西。 http://docs.mongodb.org/manual/reference/database-references/#dbrefs说得很清楚:

  

DBRef中字段的顺序很重要,使用DBRef时必须使用上述顺序。

驱动程序受益于BSON中的字段顺序一致以识别DBRef,因此您可以执行以下操作:

db.someCollection.find({ $expr: { 
    $let: {
        vars: {firstKey: { $arrayElemAt: [ { $objectToArray: "$someRef" }, 0] } },
        in: { $eq: [{ $substr: [ "$$firstKey.k", 1, 2 ] } , "id"]}
    }
} } )

将返回对象,这些对象的字段顺序与驾驶员的期望不符。