【问题标题】:Mongodb : Advanced conditional queryMongodb:高级条件查询
【发布时间】:2014-12-18 18:20:09
【问题描述】:

我有以下文档列表:(该集合有 100 多个文档)

{name : 'Tom', gender : 'male'},
{name : 'Sandra', gender : 'female'},
{name : 'Alex', gender : 'male'}

我想要的是只返回 4 条记录,其中 2 条是男性,2 条是女性。

到目前为止,我已经尝试过:

db.persons.find({'gender' : { $in : ['male','female']},{$limit : 4});

按预期带来了 4 条记录,但不能保证准确的有 2 条男性和 2 条女性。有什么方法可以过滤文档以返回指定的列表,并且不需要进行两个单独的数据库调用?

提前致谢。

【问题讨论】:

  • 如果只有三条记录,你怎么能得到四条记录?
  • @LutzHorn 因为他只展示了一个例子?
  • 然后写“我有以下文件列表”不是一个好主意。 db.persons.find() 将返回所要求的所有内容。

标签: mongodb


【解决方案1】:

我一直在努力为您的问题找到有效的解决方案,但这似乎并非易事。

我认为可以调用数据库一次的唯一方法是按性别对信息进行分组,然后通过切片并将数组大小限制为 2 来投影结果名称数组。

这在聚合管道中是不可能的,因为您不能使用 $slice 等运算符。

不过,我还是设法按性别对数据库条目进行分组,并以数组的形式返回值,然后可以对其进行操作。

经过多次尝试,我想出了以下解决方案:

var people = db.people.aggregate([
    {
        $group: {
            _id: '$gender',
            names: { $push: '$name'}
        }
    }
]).toArray();

var new_people = [];

for (var i = 0; i < people.length; i++) {
    for (var j = 0; j < 2; j++) {
        new_people.push({
            gender: people[i]._id,
            name: people[i].names[j]
        });
    }
}

如果你想过滤数据,你有两个选择,基于我的例子:

  • $match阶段内过滤聚合管道中的数据

  • 在遍历聚合结果数组时过滤数据

【讨论】:

  • 下面的可能会更好,因为您实际上可以对其使用覆盖查询,而且它不需要内存组
  • @Sammaye 可能。我还没有进行测试来比较它们。我试图帮助 OP 找到一种只向数据库发出一次调用的方法。我承认我没有关注性能:)
  • 我喜欢这个解决方案。谢谢+1
  • @I_Debug_Everything 很高兴能帮到你! :)
【解决方案2】:

打两个电话很容易,我看不出有什么理由不打。

收集两个finds的结果:

var males = db.person.find({"gender": "male"}, {"name":1}).limit(2);
var females = db.person.find({"gender": "female"}, {"name":1}).limit(2);
var all = [];
var collectToAll = function(person) { all.push(person); };
males.forEach(collectToAll)
females.forEach(collectToAll)

那么all就是

[
        {
                "_id" : ObjectId("549289765732b52ca191fdae"),
                "name" : "Tom"
        },
        {
                "_id" : ObjectId("549289865732b52ca191fdb0"),
                "name" : "Alex"
        },
        {
                "_id" : ObjectId("549289805732b52ca191fdaf"),
                "name" : "Sandra"
        }
]

【讨论】:

  • 我知道,但我正在寻找一种方法来投影我的结果以进行指定的过滤。我不想进行多个数据库调用。
  • @I_Debug_Everything 在这种情况下,就像 SQL 一样,使用它比根据服务器端的性能对它们进行分组更容易