Mongodb 使用 $or 在分片环境中更新
Mongodb update in sharded environment using $or
我在分片环境中执行了更新,例如:
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 }
我如何使用片键上的 $or 谓词执行这种更新?
谢谢
这里的主要问题是,如果没有更新语句的 "multi" 参数,您的 $or
条件就没有多大意义。至少分片条件逻辑是这么认为的,即使您的意图是只匹配单个文档。
在与 mongos
路由器一起使用的分片管理器的 "mind" 中,期望您要么针对单个分片或键范围,要么要求访问可能的品种或碎片。
这里是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" 条件中清楚地看到的那样,这里的期望是查询中有 "shard key" 的定义,或者至少有一个确切的 _id
以促进精确匹配。
因此,关于使此对分片更新有效的两个规定是:
在带有查询条件的分片键中的可能值上包含一个 "range"。我不知道您的分片键,所以我无法真正提供样本。但基本上:
{
"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 }
)
这使得选择 "possibly" 匹配多个,因此无需目标分片键即可有效地搜索分片。
在任何一种情况下,您至少 "intend" 搜索分片中的条件以找到符合您给定条件的东西或 "things" 的逻辑得到满足。
作为附加说明,然后还要考虑"upsert"操作有类似的限制,一般原则是需要解决分片键,否则操作无效,因为需要指示要插入新数据的分片。
我在分片环境中执行了更新,例如:
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 }
我如何使用片键上的 $or 谓词执行这种更新?
谢谢
这里的主要问题是,如果没有更新语句的 "multi" 参数,您的 $or
条件就没有多大意义。至少分片条件逻辑是这么认为的,即使您的意图是只匹配单个文档。
在与 mongos
路由器一起使用的分片管理器的 "mind" 中,期望您要么针对单个分片或键范围,要么要求访问可能的品种或碎片。
这里是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" 条件中清楚地看到的那样,这里的期望是查询中有 "shard key" 的定义,或者至少有一个确切的 _id
以促进精确匹配。
因此,关于使此对分片更新有效的两个规定是:
在带有查询条件的分片键中的可能值上包含一个 "range"。我不知道您的分片键,所以我无法真正提供样本。但基本上:
{ "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 } )
这使得选择 "possibly" 匹配多个,因此无需目标分片键即可有效地搜索分片。
在任何一种情况下,您至少 "intend" 搜索分片中的条件以找到符合您给定条件的东西或 "things" 的逻辑得到满足。
作为附加说明,然后还要考虑"upsert"操作有类似的限制,一般原则是需要解决分片键,否则操作无效,因为需要指示要插入新数据的分片。