我有以下文件清单:(该集合有超过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个女性。有没有什么办法可以过滤文件来返回指定的列表,也不需要进行两次单独的数据库调用?
提前致谢。
答案 0 :(得分:3)
我一直在努力为您的问题找到有效的解决方案,但看起来这并非易事。
我认为可以调用数据库一次的唯一方法是按性别对信息进行分组,然后通过对结果名称数组进行切片并将数组大小限制为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
阶段
循环聚合结果数组时过滤数据
答案 1 :(得分:1)
拨打两个电话很容易,我认为没有理由不制作它们。
收集两个find
的结果:
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"
}
]