我在分片环境中执行了更新,例如:
db.collection.update({$or:[{a:2,b:3},{a:3,b:2}]},{$set:{x:5}})
但我收到此错误消息:
update { q: { $or: [ {a:2,b:3},{a:3,b:2} ] }, u: {$set:{x:5}}, multi: false, upsert: false } does not contain _id or shard key for pattern { a: 1.0, b: 1.0 }
如何使用分片键上的$或谓词执行此类更新?
由于
答案 0 :(得分:1)
这里的主要问题是,如果没有update语句的“multi”参数,那么$or
条件就没有多大意义。至少分片条件逻辑是这样认为的,即使你的意图只是匹配单个文档。
在使用mongos
路由器的分片管理器的“头脑”中,期望您要么定位单个分片或一系列键,要么就是要求访问可能的变种或分片。
以下是actual code处理此内容以供参考:
// Validate that single (non-multi) sharded updates are targeted by shard key or _id
if (!updateDoc.getMulti() && shardKey.isEmpty() && !isExactIdQuery(updateDoc.getQuery())) {
return Status(ErrorCodes::ShardKeyNotFound,
stream() << "update " << updateDoc.toBSON()
<< " does not contain _id or shard key for pattern "
<< _manager->getShardKeyPattern().toString());
}
因此,您应该清楚地看到“if”条件,这里的期望是查询中存在“分片键”的定义,或者至少是精确的_id
以便于确定匹配。
因此,关于通过分片更新有效的两条规定是:
使用查询条件在分片键中包含可能值的“范围”。我不知道你的碎片键,所以我不能真正给出样品。但基本上是:
{
"shardKey": { "$gt": minShardKey, "$lt": maxShardKey },
"$or": [
{ "a": 2, "b": 3 },
{ "a": 3, "b": 2 }
]
}
作为查询条件,其中minShardkey
和maxShardKey
引用该范围内该键上的最小和最大可能值(在假设的“shardKey”字段上),以便经理认为你真的打算搜索所有分片。
在更新中包含“multi”选项,如下所示:
db.collection.update(
{ "$or":[
{ "a": 2, "b": 3 },
{ "a": 3, "b": 2 }
]},
{ "$set": { "x":5 } },
{ "multi": true }
)
这使得选择“可能”匹配多个,因此无需搜索目标分片密钥即可用于搜索分片。
在任何一种情况下,逻辑都是满足的,因为你至少“打算”搜索分片中的条件,以找到与你给出的条件相匹配的东西或“东西”。
作为补充说明,还要考虑“upsert”操作有类似的限制,并且一般原则是需要解决分片键,否则操作无效,因为需要作为插入新数据的碎片的一些指示。