我有一组计算机主机,每个主机都有一个嵌入的文档,其中包含网络数据,即ip地址和cidr网络。
填充集合时,我发现多个网络是重复的,它们也具有相同的ObjectId:
"_id" : ObjectId(""5b683363b873ea53ed3b55f0""),
"fqdn" : "server.mydomain.com",
"internalid" : 116852,
"network_data" : [
{
"_id" : ObjectId(""5b683363b873ea53ed3b55f1""),
"address" : "192.168.37.30",
"network" : "192.168.37.0/24"
},
{
"_id" : ObjectId(""5b683363b873ea53ed3b55f1""),
"address" : "192.168.37.30",
"network" : "192.168.37.0/24"
}
]
这怎么可能?我很确定服务器端插入正确执行。我正在使用MongoDb v3.4.9和Doctrine Mongodb-odm v1.2。
[EDIT]要添加一些信息,这是在插入操作期间收集的日志:
2018-08-06T13:39:15.806+0200 D COMMAND [conn2] run command adamongo.$cmd { update: "RawNodeData", ordered: true, updates: [ { q: { _id: ObjectId('5b683363b873ea53ed3b55f0') }, u: { $push: { ipAddresses: { $each: [ { _id: ObjectId('5b683363b873ea53ed3b55f1'), address: "192.168.37.30", network: "192.168.37.0/24" } ] } } }, upsert: false, multi: false } ], writeConcern: { w: 1 } }
2018-08-06T13:39:15.806+0200 I WRITE [conn2] update adamongo.RawNodeData query: { _id: ObjectId('5b683363b873ea53ed3b55f0') } planSummary: IDHACK update: { $push: { ipAddresses: { $each: [ { _id: ObjectId('5b683363b873ea53ed3b55f1'), address: "192.168.37.30", network: "192.168.37.0/24" } ] } } } keysExamined:1 docsExamined:1 nMatched:1 nModified:1 numYields:0 locks:{ Global: { acquireCount: { r: 1, w: 1 } }, Database: { acquireCount: { w: 1 } }, Collection: { acquireCount: { w: 1 } } } 0ms
2018-08-06T13:39:15.806+0200 I COMMAND [conn2] command adamongo.$cmd command: update { update: "RawNodeData", ordered: true, updates: [ { q: { _id: ObjectId('5b683363b873ea53ed3b55f0') }, u: { $push: { ipAddresses: { $each: [ { _id: ObjectId('5b683363b873ea53ed3b55f1'), address: "192.168.37.30", network: "192.168.37.0/24" } ] } } }, upsert: false, multi: false } ], writeConcern: { w: 1 } } numYields:0 reslen:59 locks:{ Global: { acquireCount: { r: 1, w: 1 } }, Database: { acquireCount: { w: 1 } }, Collection: { acquireCount: { w: 1 } } } protocol:op_query 0ms
似乎有两个具有相同ID和数据的更新操作。
[已解决]经过几次试验,我找到了一种有效的方法来处理可能存在重复项的文档批处理:
// multiple persist
$dm->persist($document);
// batch insertion
try {
// commit
$dm->flush(null, ['continueOnError' => true, 'ordered' => false]);
} catch (Exception $e) {
$logger->warning("some duplicates found");
} finally {
// clear
$dm->clear();
}
如果批处理中存在重复项,则 flush 方法会继续插入其他文档,然后引发异常。
需要 finally 子句,因为必须始终执行 clear 方法,以避免重复插入同一文档。
在这里,主机具有唯一索引,而嵌入式网络则没有。因此,在我的情况下,跳过 clear 操作是网络数据重复插入的原因。