nodejs操作mongodb之七(mongoose聚合函数的使用)

489 阅读2分钟

一、使用聚合函数多表查询和mongodb类似的

  • 1、定义schema

    const mongoose = require('./db');
    
    const OrderSchema = mongoose.Schema({
        order_id: String,
        uid: Number,
        trade_no: String,
        all_price: Number,
        all_num: Number,
    })
    
    module.exports = mongoose.model('Order', OrderSchema, 'order');
    
  • 2、查询数据

    const OrderModel = require('./model/order');
    
    OrderModel.aggregate([
        {
            $lookup: {
                from: 'order_item', // 关联到的表
                localField: 'order_id', // order表的字段
                foreignField: 'order_id', // order_item表的字段
                as: 'item' // 定义返回数据的字段
            }
        },
        {
            $match:{"all_price":{$gte:90}}
        }
        // ...继续写别的聚合函数
    ], (err, docs) => {
        if (err) {
            console.log('查询错误');
        } else {
            console.log(JSON.stringify(docs));
        }
    })
    

二、从order_item数据表查询到order表的数据

  • 1、方式一(比较复杂的方式)

    var mongoose=require('./db.js');
    
    var OrderItemSchema=mongoose.Schema({
        order_id:String,
        title:String,
        price:Number,   
        num:Number    
    })
    module.exports=mongoose.model('OrderItem',OrderItemSchema,'order_item');
    
    // 先根据order_item的id去查找到当前的order_item数据,再根据order_id字段去order表查询数据
    OrderItemModel.findOne({ "_id": "5b743da92c327f8d1b360546" }, function (err, docs) {
        var order_item = JSON.parse(JSON.stringify(docs));
        var order_id = order_item.order_id;
        OrderModel.find({ "order_id": order_id }, function (err, order) {
            order_item[0].order_info = order[0];
            console.log(order_item)
        })
    })
    
  • 2、方式二(使用聚合函数)

    const OrderModel = require('./model/order');
    const OrderItemModel = require('./model/order_item');
    const mongoose = require('mongoose');
    
    // 从order_item查询到order表
    OrderItemModel.aggregate([
        // 使用多表的关联查询从order_item查询到order
        {
            $lookup: {
                from: 'order',
                localField: 'order_id',
                foreignField: 'order_id',
                as: 'order_info'
            }
        },
        // 查询到的数据根据order表的id过滤
        {
            $match:{_id: mongoose.Types.ObjectId('5e0fd4bb08ad70786fd8ac87')}
        }
    ], (err, docs) => {
        if (err) {
            console.log('查询错误');
        } else {
            console.log(JSON.stringify(docs));
        }
    })
    

二、在mongoose中创建一对多的关联关系的schema

上面的方式仅仅是比较笨的方式自己手动的关联到关联数据表的字段。下面介绍使用mongoose.Types.ObjectId的方式去关联别的表。以案例:

  • 1、老师与学生的关系创建两个表(主要功能有)

    • 一个班级可以有多个学生
    • 通过班级查询到全部的学生
    • 通过学生查询到其所在班级
  • 2、创建班级的schema

    const mongoose = require('./db');
    
    const ClasssSchema = new mongoose.Schema({
      name: {
        type: String,
        require: [true, '此项为必填内容'],
      },
      // 定义班级下面的学生,因为一个班级可以是多个学生,所以可以定义为数组
      students: [
        {
          type: mongoose.Schema.Types.ObjectId,
          ref: 'student',
        }
      ]
    });
    module.exports = mongoose.model('Classs', ClasssSchema, 'classs');
    
  • 3、定义学生的schema

    const mongoose = require('./db');
    
    const StudentSchema = new mongoose.Schema({
      name: {
        type: String,
        require: [true, '此项为必填内容'],
      },
      age: Number,
    });
    
    module.exports = mongoose.model('Student', StudentSchema, 'student');
    
  • 4、添加学生与班级数据

    const ClasssModel = require('./model/classs');
    const StudentModel = require('./model/student');
    
    // 多次添加学生
    const student = new StudentModel({
      name: '马六',
      age: 35,
    });
    student.save();
    
    // 添加班级
    const cls = new ClasssModel({
      name: "初中一班",
      students: [
        "5e129534c02d70632fd168dc", // id直接去数据库查看复制进去的
        "5e1297c02069166b52e34ee4"
      ]
    });
    cls.save();
    
  • 5、通过班级查询到全部的学生信息

    ClasssModel.aggregate([
      {
        $lookup: {
          from: 'student', // 关联到学生表
          localField: 'students', // 班级表中关联的字段
          foreignField: '_id', // 学生表中被关联的id
          as: 'students',
        }
      }
    ], (err, docs) => {
      if (err) {
        console.log('查询错误', err);
        return
      }
      console.log(JSON.stringify(docs));
    })
    
  • 6、通过学生查询其所在的班级

    StudentModel.aggregate([
      {
        $lookup: {
          from: 'classs', // 关联到班级表
          localField: '_id', // 学生的id
          foreignField: 'students', // 关联到班级表中的字段
          as: 'cls',
        }
      },
      {
        $project: {
          "name": 1,
          "age": 1,
          "cls.name": 1
        }
      }
    ], (err, docs) => {
      if (err) {
        console.log('查询错误', err);
        return
      }
      console.log(JSON.stringify(docs));
    })
    

三、使用聚合函数进行三表联合查询

  • 1、三张表分别为

    • 用户表(一个用户可能有多篇文章)
    • 文章表(一篇文章只能有一个作者,但是可以有多分类)
    • 文章分类表
  • 2、定义三个schema

    // category.js
    const mongoose = require('./db');
    
    const CategorySchema = new mongoose.Schema({
      title: String,
    })
    
    module.exports = mongoose.model('Category', CategorySchema, 'category');
    
    // user.js
    var mongoose = require('./db.js');
    
    var UserSchema = new mongoose.Schema({
      name: String,
      age: Number,
      mobile: Number,
      status: {
        type: Number,
        default: 1
      }
    });
    
    module.exports = mongoose.model('User', UserSchema, 'user');
    
    // article.js
    const mongoose = require('./db');
    
    const ArticleSchema = new mongoose.Schema({
      title: String,
      category: [
        {
          type: mongoose.Schema.Types.ObjectId,
          ref: 'category',
        }
      ],
      author: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'author',
      },
      description: String,
      content: String,
    });
    
    module.exports = mongoose.model('Article', ArticleSchema, 'article');
    
  • 3、创建数据

    const CategoryModel = require('./model/category');
    const UserModel = require('./model/user');
    const ArticleModel = require('./model/article');
    
    // 添加用户
    const user = new UserModel({
      name: '李四',
      age: 20,
      mobile: 120,
    });
    user.save();
    
    //添加分类
    const category1 = new CategoryModel({
      title: 'nodejs',
    });
    const category2 = new CategoryModel({
      title: 'python',
    });
    const category3 = new CategoryModel({
      title: 'nestjs',
    });
    category1.save();
    category2.save();
    category3.save();
    
    // 文章一
    const article1 = new ArticleModel({
      title: 'nest开发',
      category: [
        '5e12a06bad979e89f8976851', // 从数据库中复制过来的
        '5e129fd242616287b39dc55c', // 从数据库中复制过来的
      ],
      author: '5e129f6bdc449e8610bdc1f8', // 从数据库中复制过来的
      description: 'nestjs连接mongodb',
      content: '省去1000个字',
    })
    
    article1.save();
    // 文章二
    const article2 = new ArticleModel({
      title: 'python开发',
      category: [
        '5e129fd242616287b39dc55d', // 从数据库中复制过来的
      ],
      author: '5e129f7678a95b8648ebb471', // 从数据库中复制过来的
      description: 'python基础开始',
      content: '省去1000个字',
    })
    
    article2.save();
    
  • 4、文章表查询数据

    // 根据文章表查询到文章、分类、作者
    ArticleModel.aggregate([
      {
        $lookup: {
          from: 'category',
          localField: 'category',
          foreignField: '_id',
          as: 'category',
        }
      },
      {
        $lookup: {
          from: 'user',
          localField: 'author',
          foreignField: '_id',
          as: 'user',
        }
      },
    ], (err, docs) => {
      if (err) {
        console.log('查询错误', err);
        return
      }
      console.log(JSON.stringify(docs));
    })
    

  • 5、用户表查询到文章

    UserModel.aggregate([
      {
        $lookup: {
          from: 'article',
          localField: '_id',
          foreignField: 'author',
          as: 'article',
        }
      },
    ], (err, docs) => {
      if (err) {
        console.log('查询错误', err)
        return
      }
      console.log(JSON.stringify(docs));
    })