鉴于:Mongo 允许使用“点”设置嵌套字段,例如:

rs0:PRIMARY> db.tmp.update({ a: 1 }, { $set: { 'b.c': 2 } }, { upsert: true })
rs0:PRIMARY> db.tmp.findOne()
{
    "_id" : ObjectId("558251c6a3354af70d70f3cc"),
    "a" : 1,
    "b" : {
        "c" : 2
    }
}

在这个例子中,记录是由 upsert 创建的,我可以在 oplog 中验证:
rs0:PRIMARY> use local
rs0:PRIMARY> db.oplog.rs.find().sort({ts:-1}).limit(1).pretty()
{
    "ts" : Timestamp(1434603974, 2),
    "h" : NumberLong("2071516013149720999"),
    "v" : 2,
    "op" : "i",
    "ns" : "test.tmp",
    "o" : {
        "_id" : ObjectId("558251c6a3354af70d70f3cc"),
        "a" : 1,
        "b" : {
            "c" : 2
        }
    }
}

当我做同样的事情并且记录只是更新而不是创建时,我似乎得到了相同的行为:
rs0:PRIMARY> db.tmp.update({ a: 1 }, { $set: { 'b.d': 3 } }, { upsert: true })
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
rs0:PRIMARY> db.tmp.findOne()
{
    "_id" : ObjectId("558251c6a3354af70d70f3cc"),
    "a" : 1,
    "b" : {
        "c" : 2,
        "d" : 3
    }
}

但是 ,这次 oplog 中的条目结构不同:
rs0:PRIMARY> use local
rs0:PRIMARY> db.oplog.rs.find().sort({ts:-1}).limit(1).pretty()
{
    "ts" : Timestamp(1434604173, 1),
    "h" : NumberLong("-4353495487634403370"),
    "v" : 2,
    "op" : "u",
    "ns" : "test.tmp",
    "o2" : {
        "_id" : ObjectId("558251c6a3354af70d70f3cc")
    },
    "o" : {
        "$set" : {
            "b.d" : 3
        }
    }
}

(注意 "b.d" 键)。

这给我带来了问题,因为我试图通过检查相应的 oplog 条目来调查一些丢失的更新,但 AFAICT 无法查询设置特定嵌套字段的 oplog 条目:
rs0:PRIMARY> db.oplog.rs.findOne({ 'o.$set.b.d': { $exists: true } })
null

有什么方法可以查询 oplog 中与特定嵌套字段更新有关的条目(在本例中为 b.d )?

似乎我遇到了 Mongo 的 prohibition of dots in field-names 不一致的应用程序:一方面我无法创建(通过官方客户端/直接在 Mongo shell 中)或查询它们,但另一方面它正在 oplog 中创建它们,离开不可查询的 oplog 条目。

任何帮助将非常感激。

为了完整起见,请注意,我可以使用包含 $set 位的键成功查询 oplog 条目:
rs0:PRIMARY> db.tmp.update({ a: 1 }, { $set: { e: 4 } }, { upsert: true })
rs0:PRIMARY> use local
rs0:PRIMARY> db.oplog.rs.findOne({ 'o.$set.e': { $exists: true } })
{
    "ts" : Timestamp(1434604486, 1),
    "h" : NumberLong("1819316318253662899"),
    "v" : 2,
    "op" : "u",
    "ns" : "test.tmp",
    "o2" : {
        "_id" : ObjectId("558251c6a3354af70d70f3cc")
    },
    "o" : {
        "$set" : {
            "e" : 4
        }
    }
}

最佳答案

您是对的,MongoDB 的 oplog 实现中存在一些不一致之处,它允许每个 op 日志的文档格式在技术上不允许相应地查询此类文档。

即使插入相同的条目也是不可能的,因为它有一个 $set 字段名称:

db.tmp2.insert({
    "ts" : Timestamp(1450117240, 1),
    "h" : NumberLong(2523649590228245285),
    "v" : NumberInt(2),
    "op" : "u",
    "ns" : "test.tmp",
    "o2" : {
        "_id" : ObjectId("566f069e63d6a355b2c446af")
    },
    "o" : {
        "$set" : {
            "b.d" : NumberInt(4)
        }
    }
})

2015-12-14T10:27:04.616-0800 E QUERY    Error: field names cannot start with $ [$set]
    at Error (<anonymous>)
    at DBCollection._validateForStorage (src/mongo/shell/collection.js:161:19)
    at DBCollection._validateForStorage (src/mongo/shell/collection.js:165:18)
    at insert (src/mongo/shell/bulk_api.js:646:20)
    at DBCollection.insert (src/mongo/shell/collection.js:243:18)
    at (shell):1:9 at src/mongo/shell/collection.js:161


并且 b.d 对 key 无效

db.tmp.update({ a: 1 }, { $set: { 'b.d': 4 } }, { upsert: true })
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.oplog.rs.find()


db.tmp2.insert({
    "ts" : Timestamp(1450117240, 1),
    "h" : NumberLong(2523649590228245285),
    "v" : NumberInt(2),
    "op" : "u",
    "ns" : "test.tmp",
    "o2" : {
        "_id" : ObjectId("566f069e63d6a355b2c446af")
    },
    "o" : {
        "set" : {
            "b.d" : NumberInt(4)
        }
    }
})

2015-12-14T10:23:26.491-0800 E QUERY    Error: can't have . in field names [b.d]
    at Error (<anonymous>)
    at DBCollection._validateForStorage (src/mongo/shell/collection.js:157:19)
    at DBCollection._validateForStorage (src/mongo/shell/collection.js:165:18)
    at DBCollection._validateForStorage (src/mongo/shell/collection.js:165:18)
    at insert (src/mongo/shell/bulk_api.js:646:20)
    at DBCollection.insert (src/mongo/shell/collection.js:243:18)
    at (shell):1:9 at src/mongo/shell/collection.js:157


也许应该记录一个 Jira 问题,建议将 $set 搜索的语法设置为一个值:

{
    "ts" : Timestamp(1450117240, 1),
    "h" : NumberLong(2523649590228245285),
    "v" : NumberInt(2),
    "op" : "u",
    "ns" : "test.tmp",
    "o2" : {
        "_id" : ObjectId("566f069e63d6a355b2c446af")
    },
    "o" : {
        "$set" : {
            "key" : "b.d"
            "value" : NumberInt(4)
        }
    }
}


更新:为此创建了一个 Jira 问题:

https://jira.mongodb.org/browse/SERVER-21889

关于MongoDB oplog 在键名中有带点的记录,无法查询,afaict,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30907116/

10-10 22:10