使用$或者在分片环境中更新Mongodb

时间:2015-08-21 12:59:46

标签: mongodb mongodb-query sharding

我在分片环境中执行了更新,例如:

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 }

如何使用分片键上的$或谓词执行此类更新?

由于

1 个答案:

答案 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以便于确定匹配。

因此,关于通过分片更新有效的两条规定是:

  1. 使用查询条件在分片键中包含可能值的“范围”。我不知道你的碎片键,所以我不能真正给出样品。但基本上是:

    { 
        "shardKey": { "$gt": minShardKey, "$lt": maxShardKey },
        "$or": [
           { "a": 2, "b": 3 },
           { "a": 3, "b": 2 }
        ]
    }
    

    作为查询条件,其中minShardkeymaxShardKey引用该范围内该键上的最小和最大可能值(在假设的“shardKey”字段上),以便经理认为你真的打算搜索所有分片。

  2. 在更新中包含“multi”选项,如下所示:

     db.collection.update(
        { "$or":[
            { "a": 2, "b": 3 },
            { "a": 3, "b": 2 }
        ]},
        { "$set": { "x":5 } },
        { "multi": true }
     )
    

    这使得选择“可能”匹配多个,因此无需搜索目标分片密钥即可用于搜索分片。

  3. 在任何一种情况下,逻辑都是满足的,因为你至少“打算”搜索分片中的条件,以找到与你给出的条件相匹配的东西或“东西”。

    作为补充说明,还要考虑“upsert”操作有类似的限制,并且一般原则是需要解决分片键,否则操作无效,因为需要作为插入新数据的碎片的一些指示。