草庐IT

MongoDB 复合分片键

coder 2023-11-05 原文

我对 Mongo 复合分片键有疑问。假设我有这样结构的文档:

{
   "players": [
      {
        "id": "12345",
        "name": "John",
      },
      {
        "id": "23415",
        "name": "Doe",
      }
   ]
}

Players embedded documents are always present and always 2. 我认为“players.0.id”和“players.1.id”作为分片键应该是一个不错的选择,因为它们不是单调的并且分布均匀。

我无法从文档中理解的是:

  1. 所有具有相同“players.0.id”或相同“players.1.id”的文档应该保存到同一个 block 中,或者
  2. 所有具有相同“players.0.id”和相同“players.1.id”的文档都应该保存到同一个 block 中。

换句话说,如果我查询集合以获取 John(作为玩家 1 或玩家 2)玩过的所有游戏,查询将发送到一个 block 还是所有 block ?

最佳答案

您不能创建部分键是多键索引(即数组字段上的索引)的分片键。 Shard Key Index Type 中提到了这一点:

A shard key index cannot be an index that specifies a multikey index, a text index or a geospatial index on the shard key fields.

如果 players 字段下正好有两个项目,为什么不创建两个子文档而不是使用数组呢?数组通常适用于文档中有多项不确定编号的用例。例如,此结构可能适用于您的用例:

{
    "players": {
        "player_1": {
            "id" : 12345,
            "name": "John"
        },
        "player_2": {
            "id": 54321,
            "name": "Doe"
        }
    }
}

然后您可以创建一个索引,如:

> db.test.createIndex({'players.player_1.id':1, 'players.player_2.id':1})

回答你的问题,如果你使用这个片键,那么:

  1. 不能保证相同的 player_1.idplayer_2.id 会在同一个 block 上。这将取决于您的数据分布。

  2. 如果您以 player_1 OR player_2 的身份查询 John,查询将发送到所有分片。这是因为您有一个复合索引作为分片键,并且您正在搜索非前缀字段上的精确匹配。

详细说明问题 2:

你正在做的查询是这样的:

db.test.find({$or: [
    {'players.player_1.id':123},
    {'players.player_2.id':123}
]})

在复合索引中,索引首先按player_1.id排序,然后对于每个player_1.id,存在排序后的player_2.id。例如,如果您有 10 个包含 player_1.idplayer_2.id 值组合的文档,您可以像这样可视化索引:

player_1.id | player_2.id
------------|-------------
0           | 10
0           | 123
1           | 100
1           | 123
2           | 123
2           | 150
123         | 10
123         | 100
123         | 123
123         | 150

请注意,值 player_2.id: 123 在表中出现多次,每个 player_1.id 出现一次。另请注意,对于每个 player_1.id 值,player_2.id 值都在其中排序。

这就是 MongoDB 的复合索引的工作原理及其排序方式。复合索引有更多细微差别,此处解释太长,但详细信息在 Compound Indexes page 中解释。

这种排序方法的效果是,索引中分布着许多相同的 player_2.id 值。由于整体索引仅根据 player_1.id 排序,因此如果不指定 player_1.id 则无法找到确切的 player_2.id >。因此,上述查询将发送到所有分片。

关于MongoDB 复合分片键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48598445/

有关MongoDB 复合分片键的更多相关文章

  1. ruby-on-rails - 如何在 Rails 中实现复合主键 - 2

    我有一个如下所示的User模型:classUser数据库中的users表有两个外键organization_id和department_id。如何使这两列成为复合主键?到目前为止,我在网上看到了两种方法:选项1使用composite_primary_keysgem选项2使用如下方式为两列中的每一列添加索引:add_index:users,[:organization_id,:department_id],unique:true我的问题在users表中唯一标识一行的最佳方法是什么,其中一行必须按顺序具有department_id和organization_id被唯一识别?索引两列和简单地

  2. ruby-on-rails - 在一个 Rails 应用程序中使用 PostgreSQL 的 MongoDB - 2

    我可以在一个Rails应用程序中同时使用MongoDB和PostgreSQL吗?具体来说,我最终会想要使用像MongoHQ这样的东西。到目前为止,我未能在实验中进行这项工作。令我担心的是,MongoDB文档特别指出我必须禁用ActiveRecord。任何建议将不胜感激。 最佳答案 您无需禁用ActiveRecord即可使用MongoDB。查看Mongoid只需将gem加上任何模型与您现有的任何ActiveRecord模型一起添加。您应该注意到MongoHQ只是MongoDB的托管服务,可以与任何对象文档映射器(ODM)一起使用。更多

  3. ruby-on-rails - 自定义 RESTful 资源的 url_for(复合键;不仅仅是 id) - 2

    给定以下资源定义:map.resources:posts,:except=>[:show]map.post'/:year/:month/:slug,:controller=>:posts,:action=>:show我可以让url_for为我工作,使用这个语法:'2010',:month=>'02',:slug=>'test')%>但是有没有办法让它工作呢?目前它抛出这个错误:Noroutematches{:year=>#,:controller=>"posts",:action=>"show"}显然它将@post对象传递给第一个路由参数(看起来像一个Rails错误...)。但是我可以

  4. ruby - 使用 mongodb/mongoid 运行时更改模型 - 2

    我必须在mongoid模型中添加几个字段,我知道MongoDB没有迁移,但如果我继续而不删除数据库,使rails完全“重新生成”数据库,它不会显示或使用新的领域!去这里最好的方法是什么?有比删除/重新打开mongodb更软的东西吗?提前致谢卢卡 最佳答案 一般来说,应该可以在运行时用新字段更新旧文档。MongoDB中不需要迁移。您可能想编写rake任务以使用新字段和默认值更新旧文档。您可以通过检查那些默认值为nil的新字段来找到这些文档。更新简单风格:如果您使用默认值定义一个新字段,只要您设置了一个新值,就应该始终使用该值:应用程序

  5. ruby-on-rails - 我如何从 Ruby 代码连接到 mongodb? - 2

    我如何从Ruby代码连接到mongodb? 最佳答案 首先,您必须安装MongoDbgem:geminstallmongo然后运行代码:require'rubygems'#notnecessaryforRuby1.9require'mongo'db=Mongo::Connection.new.db("mydb")#ORdb=Mongo::Connection.new("localhost").db("mydb")#ORdb=Mongo::Connection.new("localhost",27017).db("mydb")

  6. ruby - MongoDB:无法从 BSON 类型 EOO 转换为 Date - 2

    我正在尝试使用聚合框架(使用ruby​​)并像这样投影日期:db['requests'].aggregate([{"$project"=>{_id:0,method:'$method',user:'$user',year:{'$year'=>'$timestamp'}}}])文档是这样的:{_id:ObjectId("5177d7d7df26358289da7dfd"),timestamp:ISODate("2013-04-12T03:58:05+00:00"),method:"POST",status:"200",inputsize:"874",outputsize:"4981",u

  7. ruby - 在 Ruby 中从 MongoDB 中检索字段的子集 - 2

    我试图通过在Ruby中进行的查询从MongoDB获取字段的子集,但它似乎不起作用。它不返回任何结果这是ruby代码:coll.find("title"=>'Halo',:fields=>["title","isrc"])#thisdoesn'twork如果我删除字段散列,它会工作,返回包含所有字段的结果coll.find("title"=>'Halo')#thisworks查看mongodb控制台,第一个查询在mongodb服务器上结束,如下所示:{title:"Halo",fields:["title","isrc"]}如果我尝试从mongo客户端控制台进行查询,它会工作,我会得到结

  8. ruby - 是否可以使用事件记录为表定义复合主键? - 2

    这个问题在这里已经有了答案:HowtosetcompositekeyinRailsapplication(2个答案)关闭8年前。我在没有Rails的ruby​​项目中使用ActiveRecord。我需要为表定义复合主键。通常迁移会自动创建主键。是否可以使用事件记录为表定义我自己的复合主键?

  9. Elasticsearch和MongoDB对比 - 2

    文章目录Elasticsearch和MongoDB对比关于ElasticsearchElasticsearch应用场景关于MongoDBMongoDB优点mongodb适用场景Elasticsearch和MongoDB对比Elasticsearch和MongoDB开源许可协议参考Elasticsearch和MongoDB对比关于Elasticsearch官网:https://www.elastic.co/cn/elasticsearch/Elasticistheleadingplatformforsearch-poweredsolutions.Weaccelerateresultsthatma

  10. javascript - 如何使用 JSF 复合组件使页面上的 id 唯一? - 2

    我正在为名为flot的Javascript图表库制作一个组件。//这是我目前拥有的少量代码。我遇到的问题是如何使该div标记在页面上随机生成,以便我可以输出多个图表。显然,在当前状态下它不会这样做。我需要将值传递到javascript函数中。我知道我可以创建另一个需要id的属性,用户必须指定id,但我注意到很多组件不需要id。在primefaces和icefaces等繁重的ajax/javascript库中,id似乎是随机的。 最佳答案 可以通过#{cc.id}获取复合组件自身的ID。因此,为了确保唯一性,只需执行以下操作:和$.p

随机推荐