2014-01-10 166 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'来使它兼容。当然可行,但可能不适合我的用例。值得一票赞同。 –