MongoDB:对数组元素进行匹配和排序?

时间:2014-01-10 19:12:41

标签: mongodb mongoid

我有一些'产品'对象:

{ 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' }

这是'正确的',但是当我为'twitter'运行相同的查询时,我希望B-> A,但是接收与上面相同的输出。似乎没有应用where&按照我的意图将逻辑排序在一起,即“通过与'twitter'匹配的social_stat元素排序”。

我在寻找什么

  • 如何更改我的查询以反映order()对匹配的social_stat元素的应用?
  • 如果使用这些正常的MongoDB查询是不可能的,那么我可以使用聚合框架吗?那会是什么样的?
  • 然后作为奖励,如何使用Mongoid编写等效查询?

我看过一些相关链接:

2 个答案:

答案 0 :(得分: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"
    }}
)

'twitter'的结果:

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

'facebook'的结果:

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

答案 1 :(得分:1)

由于social_stats是一个数组,我认为你需要聚合框架或MapReduce。但是如果你将结构改为

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

......你可以这样做:

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

注意:这也需要更改您的查询!