如何通过$ lookup在“join”集合上执行$ textsearch?

我是Mongo的新手,使用v3.2。 我有2个集合父母和孩子。 我想使用Parent.aggregate并使用$ lookup来“join”Child,然后对Child中的字段执行$ text $ search,并在父级中对date范围进行search。 这可能吗…?

根据已经提出的意见,不能对$lookup的结果执行$textsearch,因为在第一个stream水线阶段以外的任何阶段都没有可用的索引。 尤其是考虑到你真的希望根据“孩子”收集的结果来进行“连接”,那么确实会更好地search“孩子”。

这带来了一个明显的结论,为了做到这一点,你可以用“ $text查询来执行“child”集合的聚合,然后$lookup “parent”而不是其他的方法。

作为一个工作示例,只是使用核心驱动程序进行演示:

 MongoClient.connect('mongodb://localhost/rlookup',function(err,db) { if (err) throw err; var Parent = db.collection('parents'); var Child = db.collection('children'); async.series( [ // Cleanup function(callback) { async.each([Parent,Child],function(coll,callback) { coll.deleteMany({},callback); },callback); }, // Create Index function(callback) { Child.createIndex({ "text": "text" },callback); }, // Create Documents function(callback) { async.parallel( [ function(callback) { Parent.insertMany( [ { "_id": 1, "name": "Parent 1" }, { "_id": 2, "name": "Parent 2" }, { "_id": 3, "name": "Parent 3" } ], callback ); }, function(callback) { Child.insertMany( [ { "_id": 1, "parent": 1, "text": "The little dog laughed to see such fun" }, { "_id": 2, "parent": 1, "text": "The quick brown fox jumped over the lazy dog" }, { "_id": 3, "parent": 1, "text": "The dish ran away with the spoon" }, { "_id": 4, "parent": 2, "text": "Miss muffet on here tuffet" }, { "_id": 5, "parent": 3, "text": "Lady is a fox" }, { "_id": 6, "parent": 3, "text": "Every dog has it's day" } ], callback ) } ], callback ); }, // Aggregate with $text and $lookup function(callback) { Child.aggregate( [ { "$match": { "$text": { "$search": "fox dog" } }}, { "$project": { "parent": 1, "text": 1, "score": { "$meta": "textScore" } }}, { "$sort": { "score": { "$meta": "textScore" } } }, { "$lookup": { "from": "parents", "localField": "parent", "foreignField": "_id", "as": "parent" }}, { "$unwind": "$parent" }, { "$group": { "_id": "$parent._id", "name": { "$first": "$parent.name" }, "children": { "$push": { "_id": "$_id", "text": "$text", "score": "$score" } }, "score": { "$sum": "$score" } }}, { "$sort": { "score": -1 } } ], function(err,result) { console.log(JSON.stringify(result,undefined,2)); callback(err); } ) } ], function(err) { if (err) throw err; db.close(); } ); }); 

这将导致每个Parent填充的Child查询中的$text匹配,以及按"score"sorting:

 [ { "_id": 1, "name": "Parent 1", "children": [ { "_id": 2, "text": "The quick brown fox jumped over the lazy dog", "score": 1.1666666666666667 }, { "_id": 1, "text": "The little dog laughed to see such fun", "score": 0.6 } ], "score": 1.7666666666666666 }, { "_id": 3, "name": "Parent 3", "children": [ { "_id": 5, "text": "Lady is a fox", "score": 0.75 }, { "_id": 6, "text": "Every dog has it's day", "score": 0.6666666666666666 } ], "score": 1.4166666666666665 } ] 

这最终是有道理的,并且比从“父母”查询在$lookup所有“子女”,然后用$match “后过滤”来删除不符合标准的任何“子女”更有效。然后随后丢弃没有任何匹配的“父母”。

mongoose式“参考”的情况也是如此,在“父”中包括“孩子”的“数组”,而不是logging在孩子身上。 因此,只要"localField"上的"localField" (在这种情况下是_id )与父types中的"foriegnField"定义的types是相同的(如果它正在使用.populate() ),那么您仍然在$lookup结果中为每个“子”获取匹配的“父”。

这一切都归结为扭转了你的思想,并认识到$text结果是最重要的事情,因此“那个”是需要启动操作的集合。

这是可能的,但只是反过来做。


在家长中使用mongoose风格与引用的孩子列表

只要显示相反的情况下对父母的引用以及date过滤:

 var async = require('async'), mongoose = require('mongoose'), Schema = mongoose.Schema; mongoose.connect('mongodb://localhost/rlookup'); var parentSchema = new Schema({ "_id": Number, "name": String, "date": Date, "children": [{ "type": Number, "ref": "Child" }] }); var childSchema = new Schema({ "_id": Number, "text": { "type": String, "index": "text" } },{ "autoIndex": false }); var Parent = mongoose.model("Parent",parentSchema), Child = mongoose.model("Child",childSchema); async.series( [ function(callback) { async.each([Parent,Child],function(model,callback) { model.remove({},callback); },callback); }, function(callback) { Child.ensureIndexes({ "background": false },callback); }, function(callback) { async.parallel( [ function(callback) { Parent.create([ { "_id": 1, "name": "Parent 1", "date": new Date("2016-02-01"), "children": [1,2] }, { "_id": 2, "name": "Parent 2", "date": new Date("2016-02-02"), "children": [3,4] }, { "_id": 3, "name": "Parent 3", "date": new Date("2016-02-03"), "children": [5,6] }, { "_id": 4, "name": "Parent 4", "date": new Date("2016-01-15"), "children": [1,2,6] } ],callback) }, function(callback) { Child.create([ { "_id": 1, "text": "The little dog laughed to see such fun" }, { "_id": 2, "text": "The quick brown fox jumped over the lazy dog" }, { "_id": 3, "text": "The dish ran awy with the spoon" }, { "_id": 4, "text": "Miss muffet on her tuffet" }, { "_id": 5, "text": "Lady is a fox" }, { "_id": 6, "text": "Every dog has it's day" } ],callback); } ], callback ); }, function(callback) { Child.aggregate( [ { "$match": { "$text": { "$search": "fox dog" } }}, { "$project": { "text": 1, "score": { "$meta": "textScore" } }}, { "$sort": { "score": { "$meta": "textScore" } } }, { "$lookup": { "from": "parents", "localField": "_id", "foreignField": "children", "as": "parent" }}, { "$project": { "text": 1, "score": 1, "parent": { "$filter": { "input": "$parent", "as": "parent", "cond": { "$and": [ { "$gte": [ "$$parent.date", new Date("2016-02-01") ] }, { "$lt": [ "$$parent.date", new Date("2016-03-01") ] } ] } } } }}, { "$unwind": "$parent" }, { "$group": { "_id": "$parent._id", "name": { "$first": "$parent.name" }, "date": { "$first": "$parent.date" }, "children": { "$push": { "_id": "$_id", "text": "$text", "score": "$score" } }, "score": { "$sum": "$score" } }}, { "$sort": { "score": -1 } } ], function(err,result) { console.log(JSON.stringify(result,undefined,2)); callback(err); } ) } ], function(err) { if (err) throw err; mongoose.disconnect(); } ); 

输出:

 [ { "_id": 1, "name": "Parent 1", "date": "2016-02-01T00:00:00.000Z", "children": [ { "_id": 2, "text": "The quick brown fox jumped over the lazy dog", "score": 1.1666666666666667 }, { "_id": 1, "text": "The little dog laughed to see such fun", "score": 0.6 } ], "score": 1.7666666666666666 }, { "_id": 3, "name": "Parent 3", "date": "2016-02-03T00:00:00.000Z", "children": [ { "_id": 5, "text": "Lady is a fox", "score": 0.75 }, { "_id": 6, "text": "Every dog has it's day", "score": 0.6666666666666666 } ], "score": 1.4166666666666665 } ] 

注意到由于date不在应用$filter的查询范围内,所以将删除否则具有最大排名的"Parent 4"