Mongoose查询,查找B.array中具有A.array匹配项的typesB的所有项目
我有一个模特Person
schemas.person = new mongoose.Schema({ firstname: {type: String}, lastname: {type: String}, age: Number, email: {type: String}, gender: {type: String}, matches: [{type: mongoose.Schema.Types.ObjectId, ref: models.Person}], });
matches
是指另一个有相似兴趣的人(即约会目的)
假设我有10个male
和10个female
。
我想写一个查询,给我一个与所有10个女性相互匹配的男性 – 也就是说,所有10个女性出现在他的matches
arrays中,他出现在所有10个女性的matches
arrays中。
所以在伪代码中,它看起来像这样:
models.Person.find({"gender": "male"}).exec(function(err, men){ models.Person.find({"gender": "female"}).exec(function(err, women){ models.Person.find(some item from men.matches $in all women.matches}, function(err, result){ console.log(result); } } });
最后一部分some item from men.matches $in all women.matches
一个some item from men.matches $in all women.matches
在Mongoose中我不知道该怎么说,我不能在网上find一个好的方法。
请注意,匹配数组看起来像:
[ { "$oid": "558ced061d35bd072e7b5825" }, { "$oid": "558ced061d35bd072e7b58a0" }, { "$oid": "558ced061d35bd072e7b58c6" } ]
有什么方法来expression这一点?
两个关键标准是每个人都有一个匹配:
- 可能匹配的
id
必须在它们的matches
数组中 - 他们的
id
必须在另一个人的matches
arrays
第三个提到的比赛是女性的标准应该已经通过包含在matches
arrays中来说明,假定这种偏好限制被反映在那里。 如果没有,为什么限制他们的比赛在这里,而不是? 这就是说,这将是一个简单的附加查询参数添加,我会留给你。 #爱赢
所以,这里有一种方法是使用find来获得所有人的列表,然后使用第二个find来检索所有可能的匹配(没有性别排斥)。
models.Person.find({ gender: "male" }).exec().then(function gotAllMen(persons) { // persons is an array of men // Find any matches for each person return new Promise.all(persons.map(function(person) { return models.Person.find({ _id: {$in: person.matches}, // Satisfies 1 matches: person._id // Satisfies 2 }).exec().then(function(match) { // Create a new object for each match return { person: person, match: match }; }); })); }).then(function matches(matches) { // Have a date });
注意:这是未经testing的代码
一种方法是先获取所有女性ID的数组,然后将这个数组与男性查询的matches
字段进行比较,最后遍历女性查询来查找匹配项。
为了帮助解释上述概念,假设您在mongo shell中创build了一个testing集合,其中包含以下文档(为了简洁明了,缩短了模式):
db.test.insert([ { "_id" : 1, "gender" : "female", "name" : "a", "matches" : [6, 10] },{ "_id" : 2, "gender" : "female", "name" : "b", "matches" : [7, 10] },{ "_id" : 3, "gender" : "female", "name" : "c", "matches" : [8, 10] },{ "_id" : 4, "gender" : "female", "name" : "d", "matches" : [9, 10] },{ "_id" : 5, "gender" : "female", "name" : "e", "matches" : [10] },{ "_id" : 6, "gender" : "male", "name" : "f", "matches" : [1, 3 ] },{ "_id" : 7, "gender" : "male", "name" : "g", "matches" : [1, 2 ] },{ "_id" : 8, "gender" : "male", "name" : "h", "matches" : [3, 5] },{ "_id" : 9, "gender" : "male", "name" : "i", "matches" : [5] },{ "_id" : 10, "gender" : "male", "name" : "j", "matches" : [1,2,3,4,5] } ])
从观察结果可以看出,满足查询条件的是给予你一个与所有5个女性相互匹配的男性的查询 – 也就是说,所有5个女性出现在他的匹配数组中,并且他出现在匹配数组中全部5名女性。
现在我们如何在mongo shell中翻译这个查询呢?
function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length != b.length) return false; a.sort(); b.sort(); for (var i = 0; i < a.length; ++i) { if (a[i] !== b[i]) return false; } return true; } var all_females = db.test.find({"gender": "female"}).map(function(p){return p._id}), male = {}, matched = {}; db.test.find({"gender": "male"}).forEach(function (m){ if (arraysEqual(m.matches, all_females)) male = m; }); var matches = db.test.find({"gender": "female", "matches": male._id}).map(function(p){return p._id}); if (arraysEqual(matches, all_females)) matched = male; printjson(matched);
输出 :
{ "_id" : 10, "gender" : "male", "name" : "j", "matches" : [1,2,3,4,5] }
现在你可以使用lodash库中的helper方法_.each()
和_.isEqual()
来实现上面的Mongoose,如下所示(未经testing):
var male = {}, matched = {}; models.Person.find({"gender": "female"}).exec(function(err, docs){ if(err) return res.send(err); var all_females = docs.map(function(p){return p._id}); models.Person.find({"gender": "male"}).exec(function(err, men){ _.each(men, function(m, i) { if (_.isEqual(all_females, m.matched)) male = m; }); models.Person.find({"gender": "female", "matches": male._id}).exec(function(err, women){ var matched_females = women.map(function(w){return w._id}); if (_.isEqual(all_females, matched_females)) matched = male; console.log(matched); }); }); });