[问题]Nodejs Mongoose如何实现统计查询、关联查询

发布于 1周前 作者 caililin 来自 nodejs/Nestjs

[问题]Nodejs Mongoose如何实现统计查询、关联查询

最近业务上提出一个需求,要求能做统计,我们设计的文档集,统计可能跨越的文档会比较多,想问一下,mongoose能实现统计查询和关联查询吗? 例如student文档对象有subject文档对象,subject文档对象有score属,查询所有学员的成绩。我个人的思路就是一般的解决方案,先查询所有学员,再查询所有分数,然后遍历做累加统计

StudentDao.find().select('_id').exec(function(err,stus){
    SubjectDao.find().where('student_id').in(stus).exec(function(err,subs){
        var sum = 0;
        for(var i = 0; i < subs.length; i++){
            sum += subs[i].score;
        }
        console.log(sum);
    });
});

心想只要提供了关联查询和统计查询,这样的代码会变得简化,不知道熟悉mongoose或者做过mongodb开发各位有没有遇见过,真心求解,谢谢!


11 回复

当然可以,Mongoose 提供了强大的功能来实现统计查询和关联查询。下面我将详细解释如何使用 Mongoose 实现这些功能,并提供一些示例代码。

统计查询

对于统计查询,我们可以使用聚合管道(Aggregation Pipeline)来完成。假设我们要计算所有学生的总成绩,可以使用 $group 操作符来对数据进行分组并计算总和。

示例代码

const mongoose = require('mongoose');
const Student = mongoose.model('Student', new mongoose.Schema({
    name: String,
    subjects: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Subject' }]
}));

const Subject = mongoose.model('Subject', new mongoose.Schema({
    student_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Student' },
    score: Number
}));

// 计算所有学生的总成绩
async function calculateTotalScore() {
    const totalScore = await Student.aggregate([
        {
            $unwind: '$subjects'
        },
        {
            $lookup: {
                from: 'subjects',
                localField: 'subjects',
                foreignField: '_id',
                as: 'subjectDetails'
            }
        },
        {
            $unwind: '$subjectDetails'
        },
        {
            $group: {
                _id: null,
                totalScore: { $sum: '$subjectDetails.score' }
            }
        }
    ]);

    console.log(totalScore); // 输出总成绩
}

calculateTotalScore();

关联查询

Mongoose 提供了 populate() 方法来实现关联查询。这样我们可以从一个模型中获取相关联的数据。

示例代码

// 查询某个学生的所有科目及其成绩
async function getStudentSubjects(studentId) {
    const student = await Student.findById(studentId)
        .populate('subjects')
        .exec();

    console.log(student);
}

getStudentSubjects('some-student-id');

总结

通过上述示例代码,我们可以看到如何使用 Mongoose 来实现统计查询和关联查询。统计查询利用了聚合管道的强大功能,而关联查询则通过 populate() 方法来简化数据访问。希望这些示例对你有所帮助!


我遇到过。。统计查询的。后来解决办法是,扫库之后重新加了个总数的字段,每次更新都对字段进行+=操作。需要总数就取总数了。。速度还最快。。

小应用用mapreduce吧。不过效率挺低的了。还是做增量好些。。无论啥数据库- -。

######mongoose api手册的统计的方法:

Kitten.where('color', 'black').count(function (err, count) {
  if (err) return handleError(err);
  console.log('there are %d black kittens', count);
})

地址:http://mongoosejs.com/docs/api.html#query_Query-count mongodb作是文件型数据库,作关联并没有什么优势.我列出其中一些方法你可以参考一下:

##一:通过mongodb的mapreduce进行查询 优点是没有数据冗余或数据不一致问题,并且不需多次查询。缺点是mongodb的mapreduce基于javascript引擎(目前是spider monkey),单线程运行,所以效率略差,不适合实时查询 ##二:通过良好的设计数据模型来做到

var postSchema = new Schema({
  author : {type : String}, 
  title : {type : String, require : true},
  content : {type : String, require : true},
  comment : {
    owner : {type : String},
    subject : {type: String, require},
    content : {type String, require}
  }
});
myPostModel.find({ 'comment.subject' : /car*/ }).exec(function(err, result){
    Do some stuff with the result...
});

对了,补充一下,还有用ref做关联,例如:

var mongoose = require('mongoose')
  , Schema = mongoose.Schema

var PersonSchema = new Schema({ name : String, age : Number, stories : [{ type: Schema.Types.ObjectId, ref: Story }] });

var StorySchema = new Schema({ _creator : { type: Schema.Types.ObjectId, ref: Person }, title : String, fans : [{ type: Schema.Types.ObjectId, ref: Person }] });

var Story = mongoose.model(‘Story’, StorySchema); var Person = mongoose.model(‘Person’, PersonSchema); #关联查询 Story .findOne({ title: /timex/ }) .populate(’_creator’) .exec(function (err, story) { if (err) return handleError(err); console.log(‘The creator is %s’, story._creator.name); // prints “The creator is Aaron” })

恩,populate是个好方法,尝试多次之后发现他比较严格,需要匹配完全疲惫model_name和schema_filed。中间用个忽略大小写就可以实现了

想问一下,三联查询怎么做? 比如A-ref-B,B-ref-C,在查A的时候把ABC都查出来

A:{
    B:{
        C:{
        }
    }
}

这么久的帖子翻出来我实在太坏了

这么久的帖子翻出来我实在太坏了

这么久的帖子 我还在学习

Mongoose 是一个基于 Node.js 的 MongoDB 对象模型工具,它可以方便地进行统计查询和关联查询。针对您的需求,我们可以使用 Mongoose 提供的聚合管道(Aggregation Pipeline)来实现统计查询,并通过引用(References)来处理关联查询。

关联查询

首先,您需要在 StudentSubject 之间建立一个引用关系。假设 Student 模型中有一个字段 subjects,它存储的是 Subject 文档的 _id

const mongoose = require('mongoose');
const { Schema } = mongoose;

const subjectSchema = new Schema({
  name: String,
  score: Number,
});

const studentSchema = new Schema({
  name: String,
  subjects: [{ type: Schema.Types.ObjectId, ref: 'Subject' }],
});

const Student = mongoose.model('Student', studentSchema);
const Subject = mongoose.model('Subject', subjectSchema);

统计查询

接下来,使用 Mongoose 的聚合方法来统计所有学生的总成绩:

async function calculateTotalScore() {
  try {
    const totalScore = await Subject.aggregate([
      {
        $group: {
          _id: null,
          totalScore: { $sum: '$score' },
        },
      },
    ]);

    console.log(totalScore[0].totalScore); // 输出总成绩
  } catch (error) {
    console.error(error);
  }
}

calculateTotalScore();

结合统计与关联查询

如果您需要结合这两个操作,可以先从 Student 中获取所有学生的 subjects,然后通过这些 subject ID 查询对应的 Subject 文档,并统计总成绩:

async function calculateStudentsTotalScore() {
  try {
    const students = await Student.find({}, '_id subjects');

    let totalScore = 0;
    for (const student of students) {
      const subjects = await Subject.find({ _id: { $in: student.subjects } }, 'score');
      totalScore += subjects.reduce((sum, subject) => sum + subject.score, 0);
    }

    console.log(totalScore);
  } catch (error) {
    console.error(error);
  }
}

calculateStudentsTotalScore();

通过上述方法,您可以更高效地完成统计查询和关联查询,避免了手动遍历和累加的繁琐步骤。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!