2014-01-10 165 views
3

我有幾個「產品」的對象:MongoDB:匹配和排序數組元素?

{ name: 'ProductA', 
    social_stats: [ 
    { name: 'facebook', 
     shares: 60 
    }, 
    { name: 'twitter', 
     shares: 0 
    } 
    ] 
} 

{ name: 'ProductB', 
    social_stats: [ 
    { name: 'facebook', 
     shares: 0 
    }, 
    { name: 'twitter', 
     shares: 30 
    } 
    ] 
} 

我想查詢「在Facebook上共享大部分產品」和「最共享產品在Twitter上」,總是從最排序,以最少的股票。

所以我對Facebook的第一個查詢看起來像:

db.videos.find({ 
    _id: { 
    social_stats: { 
     $elemMatch: { 
     name: 'facebook' 
     } 
    } 
    } 
).sort({ 
    social_stats: { 
    shares: -1 
    } 
}) 

產量:

{ name: 'ProductA' } 
{ name: 'ProductB' } 

這是「正確的」,但是當我運行「嘰嘰喳喳」,而不是,我希望同樣的查詢B-> A,但收到與上述相同的輸出。它似乎並沒有將排序邏輯應用在一起,因爲我打算這樣做,即「通過匹配'twitter'的social_stat元素排序」。

我正在尋找

  • 如何改變我的查詢,以反映訂單的應用()來social_stat元素相匹配?
  • 如果這些正常的MongoDB查詢是不可能的,這是我可以用聚合框架做的事情嗎?那會是什麼樣子?
  • 那麼作爲獎勵,如何編碼與Mongoid的等效查詢?

一些相關的鏈接我看了看:

回答

4

您不能通過數組sort()您的結果,所以這不會達到您的結果。

你最好的辦法(如MongoDB的2.4)將使用聚合框架:

db.videos.aggregate(
    // Optional: potentially take advantage of an index to only find videos with 
    //   facebook stats; could also limit to those with shares $gt 0 
    { $match: { 
     'social_stats.name' : 'facebook' 
    }}, 

    // Convert the social_stats array into a document stream 
    { $unwind: '$social_stats' }, 

    // Only match the social stats for facebook 
    { $match: { 
     'social_stats.name' : 'facebook' 
    }}, 

    // Sort in descending order 
    { $sort: { 
     'social_stats.shares' : -1 
    }}, 

    // Only include the product names & score 
    { $project: { 
     _id: 0, 
     name: "$name", 
     shares: "$social_stats.shares" 
    }} 
) 

結果 '嘰嘰喳喳':

{ 
    "result" : [ 
     { 
      "name" : "ProductB", 
      "shares" : 30 
     }, 
     { 
      "name" : "ProductA", 
      "shares" : 0 
     } 
    ], 
    "ok" : 1 
} 

結果的Facebook':

{ 
    "result" : [ 
     { 
      "name" : "ProductA", 
      "shares" : 60 
     }, 
     { 
      "name" : "ProductB", 
      "shares" : 0 
     } 
    ], 
    "ok" : 1 
} 
+0

這應該是直接翻譯成Mongoid的,但[Mongoid和MongoDB Aggregation Framework](http://blog.joshsoftware.com/2013/09/05/mongoid-and-the-mongodb-aggregation-framework/)可能是一個有益的開始。 – Stennie

+0

這正是我最終做的,聚合框架很好地完成了事情。 Mongoid有一個'Model.collection.aggregate()'函數,你可以傳遞一個命令數組來執行(即'[match,unwind,match,sort,project]'),所以它很簡單,將一個MongoDB查詢翻譯成工作與Mongoid。 –

1

由於social_stats是一個數組我認爲你需要聚合框架或MapReduce。但是,如果你改變了結構,

{ name: 'ProductB', 
    social_stats : { 
    'facebook' : {shares: 0, name : "Facebook"}, 
    'twitter' : {shares: 30, name : "Twitter"}, 
    } 
} 

...你可以這樣做:

.sort({"social_stats.facebook.shares" : -1}) 

注:這將需要改變你的查詢,以及!

+0

沒有骰子,結果相同。 –

+0

對,我沒有想到'social_stats'是一個嵌入式數組。查看我的更新。 – luttkens

+0

我認爲這是一個很好的解決方案,但我不確定它與Mongoid和Ruby類的搭配有多好。特別是,它聽起來像我需要將一個'embeds_many'關係改變成'field type:Hash'來使它兼容。當然可行,但可能不適合我的用例。值得一票贊同。 –