带有全文搜索和项目的 Mongoose 子字段聚合

Posted

技术标签:

【中文标题】带有全文搜索和项目的 Mongoose 子字段聚合【英文标题】:Mongoose sub field aggregation with full text search and project 【发布时间】:2018-03-29 11:11:21 【问题描述】:

我有一个名为 SessionMongoose 模型,其中有一个名为 course 的字段(Course 模型),我想要使用全文搜索对 sessions 执行全文搜索,我还想使用 course 子字段中的字段聚合结果并选择一些字段,例如 course日期等。 我尝试了以下方法:

Session.aggregate(
        [
            
                $match:  $text:  $search: 'web'  
            ,
             $unwind: '$course' ,
            
                $project: 
                    course: '$course',
                    date: '$date',
                    address: '$address',
                    available: '$available'
                
            ,
            
                $group: 
                    _id:  title: '$course.title', category: '$course.courseCategory', language: '$course.language' 
                
            
        ],
        function(err, result) 
            if (err) 
                console.error(err);
             else 
                Session.deepPopulate(result, 'course course.trainer 
                  course.courseCategory', function(err, sessions) 
                  res.json(sessions);
            );
            
        
    );

我的模型:

会话
    schema = new mongoose.Schema(
        
            date: 
                type: Date,
                required: true
            ,
            course: 
                type: mongoose.Schema.Types.ObjectId,
                ref: 'course',
                required: true
            ,
            palnning: 
                type: [Schedule]
            ,
            attachments: 
                type: [Attachment]
            ,
            topics: 
                type: [Topic]
            ,
            trainer: 
                type: mongoose.Schema.Types.ObjectId,
                ref: 'trainer'
            ,
            trainingCompany: 
                type: mongoose.Schema.Types.ObjectId,
                ref: 'training-company'
            ,
            address: 
                type: Address
            ,
            quizzes: 
                type: [mongoose.Schema.Types.ObjectId],
                ref: 'quiz'
            ,
            path: 
                type: String
            ,
            limitPlaces: 
                type: Number
            ,
            status: 
                type: String
            ,
            available: 
                type: Boolean,
                default: true
            ,
            createdAt: 
                type: Date,
                default: new Date()
            ,
            updatedAt: 
                type: Date
            
        ,
        
            versionKey: false
        
    );
课程
let schema = new mongoose.Schema(
    
        title: 
            type: String,
            required: true
        ,
        description: 
            type: String
        ,
        shortDescription: 
            type: String
        ,
        duration: 
            type: Duration
        ,
        slug: 
            type: String
        ,
        slugs: 
            type: [String]
        ,
        program: 
            content: 
                type: String
            ,
            file: 
                type: String
            
        ,
        audience: [String],
        requirements: [String],
        language: 
            type: String,
            enum: languages
        ,
        price: 
            type: Number
        ,
        sections: [Section],
        attachments: 
            type: [Attachment]
        ,
        tags: [String],
        courseCategory: 
            type: mongoose.Schema.Types.ObjectId,
            ref: 'course-category',
            required: true
        ,
        trainer: 
            type: mongoose.Schema.Types.ObjectId,
            ref: 'trainer'
        ,
        trainingCompany: 
            type: mongoose.Schema.Types.ObjectId,
            ref: 'training-company'
        ,
        status: 
            type: String,
            default: 'draft',
            enum: courseStatus
        ,
        path: 
            type: String
        ,
        cover: 
            type: String,
            required: true
        ,
        duration: 
            type: Number,
            min: 1
        ,
        createdAt: 
            type: Date,
            default: Date.now
        ,
        updatedAt: 
            type: Date
        
    ,
     versionKey: false 
);

我不确定我所尝试的是否会给我带来我想要的,并且我收到了关于 $unwind 运算符的错误:

MongoError:异常:$unwind 字段路径“$course”末尾的值 必须是一个数组,但是是一个 OID

任何形式的帮助都将不胜感激。

【问题讨论】:

您缺少$lookup,通过将课程对象 ID 从会话文档加入课程文档中的 ID 来提取课程文档。在$match$unwind 阶段之间插入查找阶段。像 $lookup: from: "course", localField: "course", foreignField: "_id", as: "course" 这样的东西。调整以使用正确的集合名称、本地字段和外部字段。 @Veeram 我收到了这个错误:MongoError: exception: Unrecognized pipeline stage name: '$lookup' 如果有意义的话,我的猫鼬版本是 ^4.11.12 $lookup 阶段已添加到 3.2 mongo 服务器中。看起来你不在 3.2 版本上。进入 mongo shell 并运行db.version() 进行验证。 @Veeram mongo 版本 2.6.11 【参考方案1】:

您可以尝试以下聚合。

您缺少$lookup 需要通过将课程对象 ID 从会话文档加入课程文档中的 ID 来提取课程文档。

$project 阶段以在输出中保留所需的字段。

Session.aggregate([
  
    "$match": 
      "$text": 
        "$search": "web"
      
    
  ,
  
    "$lookup": 
      "from": "courses",
      "localField": "course",
      "foreignField": "_id",
      "as": "course"
    
  ,
  
    "$project": 
      "course": 1,
      "date": 1,
      "address": 1,
      "available": 1
    
  
])

Course 是一个包含一个课程文档的数组。您可以使用$arrayElemAt 来投影文档。

 "course": "$arrayElemAt":["$course", 0]

【讨论】:

它工作正常,除了添加 $match 时,即使条件为真,例如:` $match: 'available': true ` 您是否暗示当您添加“可用”以匹配阶段时它不起作用?像 "$match": "$text": "$search": "web" , "available": true 这样的东西应该可以工作。 不,即使只有 "$match": "available": true 也不起作用 实际上,即使在输出中我也没有得到 available 属性 很难推测。只需检查您的文件并确保它与您要查找的内容相符。可能是字符串“真”值。如果问题仍然存在,请考虑创建一个包含所有详细信息的单独问题。

以上是关于带有全文搜索和项目的 Mongoose 子字段聚合的主要内容,如果未能解决你的问题,请参考以下文章

具有必填子文档字段的 Mongoose 架构

Mongoose 按标签聚合分组项目

从带有子字段的猫鼬模式生成 Graphql 类型

猫鼬,nodejs,全文搜索

在 Mongoose/MongoDB 的文档中过滤数组、子文档、数组、文档

mongoDB,带有 $sum 和 $count 的 mongoose 聚合查询