2014-07-21 88 views
3

我有一個Ruby應用程序使用Mongoid和MongoDB v2.4.6。查詢大小的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}}}} 

一旦這個工程,我需要更新它爲$大小是> 1。

這可能嗎?感覺就像我非常接近。這是一次性的清理操作,所以查詢性能不是太大問題(但是我們確實有數百萬條記錄需要更新!)

任何幫助都非常感謝!

我已經能夠達到預期的結果,但是在測試中它太慢了(需要數週的時間來運行我們的生產系統)。問題是每個記錄雙重查詢(我們有大約3000萬條記錄在製作中)。

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提供了聚合框架,可能是找到此問題的最佳方法。對這些查詢沒有直接的「mongoid」風格方法,因爲這些方法適用於處理關係文檔的現有「rails」風格。

你雖然可以通過.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