我正在更新仍在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
字段。在数以百万计的总记录中,我们有约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)}}
);
}
我们确实有一个包含大量记录的集合,需要在连接超时的地方进行更正。我们只是再次运行了脚本,它通过了剩余的记录。
可能有更好的方法可以做到这一点。我有兴趣听到更好的方法。目前,此问题已解决。
答案 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"]}
}
} } )
将返回对象,这些对象的字段顺序与驾驶员的期望不符。