2013-06-10 2 views
0

У меня есть следующее определение дока (это рубин)MongoDB: массив запросов в внедренном документе

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"] }] 

Например, я хочу знать , сколько блоков есть без непустых кодов массива (ответ является три блока) и сколько блоков есть с b во втором положении (индекс 1) (ответ есть два).

Я использую драйвер mongoid, поэтому в идеале запрос будет использовать драйвер, но обычное манго в порядке. Благодаря!

ответ

0

IMHO 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') 

Сохранение видео, таким образом, занимает около 2-п вставок в зависимости от размера codes. Но коллекции индексируются ([:num_codes] для Blocks и [:position, :value] за Code) и должны дать вам разумную производительность запроса - даже для больших коллекций. Надеюсь, это поможет.

+0

Я знаю, что должен иметь его в отдельной коллекции, но я этого не делаю; Я не могу изменить схему прямо сейчас. Вот почему я спрашиваю SO :). Но спасибо за ваш ответ. –

+0

Вы не можете изменить способ хранения вещей в MongoDB или только схему ваших входных данных? (или оба?) – Matt

+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. Также обратите внимание, что вы вернете все видеоматериалы с по меньшей мере одним массивом непустых кодов в блоке. Чтобы подсчитать блоки, вам придется выполнять обработку на стороне клиента, чтобы удалить дополнительные блоки.

Вопрос 2:

  • Сколько блоков существуют там, где массив кодов соответствует определенной строки в заданном положении?

Очень похожий ответ. Для позиции 3:

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

Извините, что не знаю Mongoid, но, надеюсь, вы можете перевести вышеизложенное.

HTH - Rob.

Edit:

Это не работает, потому что блоки вложены и кода представляет собой массив в пределах блоков.

Не думаю, что тогда я понял вопрос. Оболочка возвращает то, что я ожидаю.

Пример из оболочки (переформатирован) - сначала данные:

> 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" : [ ] } 
    ] 
} 
+0

Это не работает, потому что 'blocks' встроен, а' codes' - это массив внутри 'blocks'. –

+0

Я обновил, чтобы показать запросы, которые я ожидал от оболочки. Можете ли вы обновить вопрос с тем, что вы ожидаете от результатов запросов? –

Смежные вопросы