MongoDB:嵌入文档中的查询数组

时间:2013-06-10 22:27:42

标签: ruby mongodb mongoid

我有以下doc定义(它是红宝石)

class Block
  include Mongoid::Document

  field :index, type: Integer  # index 0,1,..  
  field :codes, type: Array    #[A, B, C,... ]

  embedded_in :Video
end

class Video
  include Mongoid::Document

  field :name, type: String
  embeds_many :blocks, :order => :index.asc
end

我想查询匹配属性video.blocks.codes,但它是嵌入式文档的数组属性。我主要想做两种类型的查询:

  • 非空/非空codes数组存在多少个块?
  • 代码数组与给定位置的某个字符串匹配的块数是多少?

以下是我想要匹配的数据示例:

video#1
blocks: [{index: 1, codes:["a","g","c"]}, {index: 2, codes: [] }]

video#2
blocks: [{index: 1, codes:["x","b","d", "e"]}, {index: 2, codes: ["x","b"] }]

例如,我想知道没有非空代码数组有多少块(答案是三个块),有多少个块第二个位置(索引1)<{1}} (答案是两个)。

我正在使用b驱动程序,所以理想情况下查询会使用驱动程序,但是简单的mongo很好。谢谢!

2 个答案:

答案 0 :(得分:1)

我认为你要找的是点符号:http://docs.mongodb.org/manual/reference/glossary/#term-dot-notation

问题1:

  
      
  • 非空/非空代码数组存在多少个块?
  •   
db.videos.find( { 'video.blocks.codes.0' : { $exists : true } } )

有效地存在数组的第零个元素。为了提高速度,您可以在video.blocks.codes上创建索引。另请注意,您将获取块中至少包含1个非空代码数组的所有视频文档。要对块进行计数,您必须进行客户端处理以删除额外的块。

问题2:

  
      
  • 代码数组与给定位置的某个字符串匹配的块数是多少?
  •   

非常相似的答案。对于职位3:

db.videos.find( { 'video.blocks.codes.3' : 'the magic code' } )

抱歉,我不知道Mongoid,但希望你能翻译上述内容。

HTH - 罗布。

编辑:

  

这不起作用,因为嵌入了块,代码是块内的数组。

我认为我不明白这个问题。 shell返回我期望的内容。

shell中的示例(重新格式化) - 首先是数据:

> db.test.find()
{ "_id" : ObjectId("51b7cfff0ccc6eb8b11c82b1"), 
  "blocks" : [    
     { "index" : 1, "codes" : [  "a", "g", "c" ] },
     { "index" : 2, "codes" : [ ] } 
  ] 
}
{ "_id" : ObjectId("51b7d0300ccc6eb8b11c82b2"), 
  "blocks" : [
     { "index" : 1, "codes" : [ "x", "b", "d", "e" ] },        
     { "index" : 2, "codes" : [ "x", "b" ] } 
  ] 
}
{ "_id" : ObjectId("51b7d0a50ccc6eb8b11c82b3"), 
  "blocks" : [ 
     { "index" : 1, "codes" : [ ] } 
  ] 
}

第一次查询:查找包含至少包含1个代码的块的所有文档:

> db.test.find( { 'blocks.codes.0' : { $exists : true } } )
{ "_id" : ObjectId("51b7cfff0ccc6eb8b11c82b1"), 
  "blocks" : [
     { "index" : 1, "codes" : [ "a", "g", "c" ] },
     { "index" : 2, "codes" : [ ] } 
   ] 
}
{ "_id" : ObjectId("51b7d0300ccc6eb8b11c82b2"), 
  "blocks" : [ 
     { "index" : 1, "codes" : [ "x", "b", "d", "e" ] },
     { "index" : 2, "codes" : [ "x", "b" ] } 
   ] 
}

第二个查询:查找第n个代码是特定值的所有文档。在这种情况下,我选择第二个(索引1)是'g'。

> db.test.find( { 'blocks.codes.1' : "g" } )
{ "_id" : ObjectId("51b7cfff0ccc6eb8b11c82b1"), 
  "blocks" : [ 
     { "index" : 1, "codes" : [ "a", "g", "c" ] },
     { "index" : 2, "codes" : [ ] } 
  ] 
}

答案 1 :(得分:0)

恕我直言Block应该是一个单独的集合,其中包含一个额外的属性num_codes(并非嵌入式,代码未经测试)。

class Video
    include Mongoid::Document
    has_many :blocks
end

class Block
    include Mongoid::Document
    belongs_to :video
    field :index
    field :num_codes
    field :codes

    # warning pseudo code ahead:
    before_save :update_codes
    def update_codes
       # set num_codes to length of codes
       # delete all codes belonging to this block and recreate them
    end
end

查询空块:Blocks.where(num_codes : 0)。这解决了要求1.

关于要求2:据我所知,MongoDB不允许您查询数组中特定索引的值(尽管我可能在这个问题上错了)。我的建议再一次是制作一个单独的集合(代码未经测试):

class Code
   include Mongoid::Document
   belongs_to :block
   field :position
   field :value
end

Code.where(position : 3, value : 'x')

根据codes的大小,保存视频大约需要2 n次插入。但是这些集合是可编制索引的([:num_codes]Blocks[:position, :value]Code)并且应该为您提供合理的查询性能 - 即使对于大型集合也是如此。希望有所帮助。