2014-07-21 1 views
3

У меня есть рубин на рельсах с использованием Mongoid и MongoDB v2.4.6.Query Mongo Встроенные документы размером

У меня есть следующая структура MongoDB, запись которой embeds_many фрагментов:

{ 
    "_id" : "76561198045636214", 
    "fragments" : [ 
    { 
     "id" : 76561198045636215, 
     "source_id" : "source1" 
    }, 
    { 
     "id" : 76561198045636216, 
     "source_id" : "source2" 
    }, 
    { 
     "id" : 76561198045636217, 
     "source_id" : "source2" 
    } 
    ] 
} 

Я пытаюсь найти все записи в базе данных, которые содержат фрагментов с повторяющимся source_ids.

Я уверен, что мне нужно использовать $ elemMatch, поскольку мне нужно запросить встроенные документы.

Я попытался

Record.elem_match(fragments: {source_id: 'source2'}) 

который работает, но не ограничивает в дубликатах.

Затем я попытался

Record.elem_match(fragments: {source_id: 'source2', :source_id.with_size => 2}) 

, который не возвращает никаких результатов (но действительный запрос). Запрос Mongoid производит:

selector: {"fragments"=>{"$elemMatch"=>{:source_id=>"source2", "source_id"=>{"$size"=>2}}}} 

После того, как это работает, мне нужно обновить его до $ size is> 1.

Возможно ли это? Мне кажется, что я очень близко. Это одноразовая операция по очистке, поэтому производительность запросов не является большой проблемой (однако у нас есть миллионы записей для обновления!)

Любая помощь очень ценится!

Я смог добиться желаемого результата, но при тестировании он слишком медленный (потребуется много недель, чтобы пройти через нашу производственную систему). Проблема заключается в двойном запросе на запись (у нас есть ~ 30 миллионов записей на производстве).

Record.where('fragments.source_id' => 'source2').each do |record| 
    query = record.fragments.where(source_id: 'source2') 
    if query.count > 1 
    # contains duplicates, delete all but latest 
    query.desc(:updated_at).skip(1).delete_all 
    end 
    # needed to trigger after_save filters 
    record.save! 
end 

ответ

1

Проблема с текущим подходом здесь является то, что стандартные формы запросов MongoDB не на самом деле «фильтр» вложенные массивы документов в любом случае. Это, по сути, то, что вам нужно, чтобы «найти дубликаты» в ваших документах здесь.

Для этого MongoDB обеспечивает структуру агрегации, как, вероятно, лучший подход к поиску этого. Не существует прямого подхода к запросам типа «мангоид», поскольку они ориентированы на существующий стиль «рельсов» для работы с реляционными документами.

Вы можете получить доступ к «мопед» форму, хотя через .collection аксессору на модели класса:

Record.collection.aggregate([ 

    # Find arrays two elements or more as possibles 
    { "$match" => { 
     "$and" => [ 
      { "fragments" => { "$not" => { "$size" => 0 } } }, 
      { "fragments" => { "$not" => { "$size" => 1 } } } 
     ] 
    }}, 

    # Unwind the arrays to "de-normalize" as documents 
    { "$unwind" => "$fragments" }, 

    # Group back and get counts of the "key" values 
    { "$group" => { 
     "_id" => { "_id" => "$_id", "source_id" => "$fragments.source_id" }, 
     "fragments" => { "$push" => "$fragments.id" }, 
     "count" => { "$sum" => 1 } 
    }}, 

    # Match the keys found more than once 
    { "$match" => { "count" => { "$gte" => 2 } } } 
]) 

Это вернет вам результаты, как это:

{ 
    "_id" : { "_id": "76561198045636214", "source_id": "source2" }, 
    "fragments": ["76561198045636216","76561198045636217"], 
    "count": 2 
} 

Это по крайней мере дает вам что-то для работы с тем, как бороться с «дубликатами» здесь

+0

Ничего себе, Нил, я абсолютно не был бы там! Спасибо работает блестяще;) – daveharris

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

  • Нет связанных вопросов^_^