MongoDB:高级条件查询

3
我有以下文件清单:(收集超过100个文档)
{name : 'Tom', gender : 'male'},
{name : 'Sandra', gender : 'female'},
{name : 'Alex', gender : 'male'}

我希望的是仅返回4个记录,其中两个为男性,两个为女性。

到目前为止,我尝试了以下内容:

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

预期结果为4条记录,但无法保证其中有2个男性和2个女性。是否有任何方法可以过滤文档以返回指定列表,并且不需要进行两次单独的数据库调用?

提前致谢。


如果只有三条记录,你怎么能得到四条记录呢? - user1907906
1
@LutzHorn因为他只展示了一个例子? - Sammaye
1
那么写“我有以下文件清单”并不是一个很好的想法。db.persons.find()会返回所有被要求的内容。 - user1907906
2个回答

3

我一直在努力寻找解决问题的有效方法,但似乎这并不是一件容易的任务。

我想到的唯一一种可能只调用一次数据库的方法是按性别分组信息,然后通过切片和限制数组大小将结果名称数组映射为数组。

由于无法使用$ 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
@Sammaye 可能会。我还没有运行测试来比较它们。我试图帮助 OP 找到一种只发出一次数据库调用的方法。我承认我没有专注于性能 :) - vladzam
我喜欢这个解决方案。谢谢 +1 - I_Debug_Everything
@I_Debug_Everything 非常高兴我能帮到您! :) - vladzam

1
做两个调用非常容易,我想不出不做它们的理由。
收集两个“查找”操作的结果:
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
1
@I_Debug_Everything 在这种情况下,就像 SQL 一样,将它们分组以便在服务器端进行性能优化比单独调试它们更容易。 - Sammaye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接