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

Dav*_*ner 4 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
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我想查询“Facebook 上分享最多的产品”和“Twitter 上分享最多的产品”,总是按分享次数从多到少排序。

所以我对 Facebook 的第一个查询如下所示:

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

产量:

{ name: 'ProductA' }
{ name: 'ProductB' }
Run Code Online (Sandbox Code Playgroud)

这是“正确的”,但是当我对“twitter”运行相同的查询时,我期望 B->A,但收到与上面相同的输出。它似乎没有按照我的意图将 where 和排序逻辑一起应用,即“按与‘twitter’匹配的social_stat 元素排序”。

我在寻找什么

  • 如何更改我的查询以反映 order() 对匹配的 Social_stat 元素的应用?
  • 如果这些普通的 MongoDB 查询无法实现,我可以使用聚合框架来做这件事吗?那会是什么样子?
  • 那么作为奖励,如何使用 Mongoid 编写等效的查询?

我查看过的一些相关链接:

Ste*_*nie 5

你不能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"
    }}
)
Run Code Online (Sandbox Code Playgroud)

“推特”的搜索结果:

{
    "result" : [
        {
            "name" : "ProductB",
            "shares" : 30
        },
        {
            "name" : "ProductA",
            "shares" : 0
        }
    ],
    "ok" : 1
}
Run Code Online (Sandbox Code Playgroud)

“脸书”的搜索结果:

{
    "result" : [
        {
            "name" : "ProductA",
            "shares" : 60
        },
        {
            "name" : "ProductB",
            "shares" : 0
        }
    ],
    "ok" : 1
}
Run Code Online (Sandbox Code Playgroud)