Nodejs mongoose 查询问题

Nodejs mongoose 查询问题

var a = new Schema({ name: ‘’, b_id: {type: Schema.ObjectId, ref: ‘b’} });

var b = new Schema({ name: ‘’, });

a: {name: ‘1’, b_id: ‘…’} {name: ‘2’, b_id: ‘…’} {name: ‘3’, b_id: ‘…’}

b: {name: ‘b1’} {name: ‘b2’} {name: ‘b3’}

a.find({}) .populate({ path: ‘b_id’, match: {‘name’: ‘b1’} }) .exec(callback);

怎么实现Inner Join ??


6 回复

在 Node.js 中使用 Mongoose 进行查询时,我们通常会用到 populate 方法来处理引用(reference)字段。你的需求是实现类似 SQL 的内连接(INNER JOIN),这可以通过组合多个条件来完成。

首先,让我们理解一下你提供的模型定义和数据结构:

模型定义

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const bSchema = new Schema({
    name: String,
});

const aSchema = new Schema({
    name: String,
    b_id: { type: Schema.Types.ObjectId, ref: 'B' } // 注意这里 ref 应该大写 B
});

const A = mongoose.model('A', aSchema);
const B = mongoose.model('B', bSchema);

数据

假设我们有以下数据:

  • b 集合包含三个文档:{ name: ‘b1’ }, { name: ‘b2’ }, { name: ‘b3’ }
  • a 集合包含三个文档,每个文档都有一个 b_id 引用 b 集合中的文档

查询实现 INNER JOIN

Mongoose 的 populate 方法默认执行的是左连接(LEFT JOIN)。如果你需要实现内连接(INNER JOIN),可以先筛选 b 集合,然后将结果作为条件传递给 populate 方法。

B.find({ name: 'b1' }, (err, bResults) => {
    if (err) return console.error(err);

    const bIds = bResults.map(b => b._id);

    A.find({ b_id: { $in: bIds } })
        .populate('b_id')
        .exec((err, aResults) => {
            if (err) return console.error(err);
            console.log(aResults);
        });
});

解释

  1. 查找 b 集合中符合条件的文档:首先通过 B.find() 获取所有 name 为 ‘b1’ 的文档。
  2. 获取这些文档的 _id:从结果中提取出 b_id 列表。
  3. a 集合中查找与这些 b_id 匹配的文档:使用 A.find() 查找 b_id 在之前获取的 bIds 列表中的所有文档。
  4. 填充 b_id 字段:最后使用 populate('b_id')b_id 字段替换为对应的 b 文档。

这种方法实际上实现了类似于 SQL 中的内连接(INNER JOIN)的效果,因为它只返回那些在 ab 集合中都存在的记录。


mongodb 的特点就是不支持 inner join

http://docs.mongodb.org/manual/core/data-modeling/

一般遇到关系数据库中jion这样的情景,尽量设计成内嵌文档,或者是局部数据的内嵌。
最没办法的情况就是,先查主文档,然后for循环查另外一个文档。

嗯好谢谢。

在Mongoose中,使用populate()方法可以实现类似于SQL中的INNER JOIN的效果。根据你的描述,你已经定义了两个Schema(a和b),并且a模型中的b_id字段引用了b模型。

根据你的需求,你想要查询所有a文档,并且只返回那些关联的b文档中name字段等于'b1'的记录。你可以通过populate()方法来实现这一点,具体代码如下:

a.find({}) // 查询所有a文档
  .populate({
    path: 'b_id', // 关联b_id字段
    match: {'name': 'b1'}, // 只填充name为'b1'的b_id
    select: 'name' // 只选择需要的字段,这里选择name字段
  })
  .exec((err, result) => {
    if (err) return console.error(err);
    console.log(result);
  });

解释

  • a.find({}):查询所有a文档。
  • .populate({...}):填充关联的b_id字段。
    • path: 'b_id':指定要填充的字段名。
    • match: {'name': 'b1'}:指定匹配条件,只有b文档中name字段值为'b1'的才会被填充。
    • select: 'name':指定只选择b文档中的name字段,这样可以减少返回的数据量。
  • .exec(callback):执行查询并调用回调函数处理结果。

以上代码会返回所有满足条件的a文档,并且每个文档中b_id字段对应的b文档将仅包含name字段等于'b1'的记录。

回到顶部