NodeJS 如何在mongoose中进行反向嵌套查询

7gyucuyw  于 2023-05-17  发布在  Node.js
关注(0)|答案(2)|浏览(115)

我有两个模型:

const UserSchema = new mongoose.Schema({
    username: String,
    name: String
})
const PostSchema = new mongoose.Schema({
    title: String,
    user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "User",
        required: true,
    }
})

我知道我可以查询一个单一的职位,如:

Post.findById(ID).populate('user')

但我如何查询一个用户的所有职位?我知道我可以做两个独立的查询,并把它们放在一起,但有没有一种方法可以做到这一点与 Mongoose API本身?

57hvy0tb

57hvy0tb1#

在这种情况下,您应该将模式反转为:

const UserSchema = new mongoose.Schema({
    username: String,
    name: String,
    posts: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: "Post",
    ]}
})
const PostSchema = new mongoose.Schema({
    title: String,
})

并查询具有所有帖子的用户为:

User.findById(ID).populate('posts')

或使用聚合方法:

User.aggregate([
    { "$match": { "_id" : ID  }},
    { "$lookup": {
      "from": posts
      "let": { "userId":"$_id" },
      "pipeline": [
    { "$match": { "$expr": { "$eq": ["$user", "$$userId"] } } }
      ],
      "as": posts
    }}
])
bejyjqdl

bejyjqdl2#

在不更改mongoose模式的情况下,您应该使用MongoDB聚合框架来执行左外连接操作。查找用户和用户的帖子。为此,我们需要使用$lookup聚合。
您还可以使用Mongoose聚合方法,而不是将聚合管道作为对象数组传递给Model.aggregate()
例如:

import mongoose from 'mongoose';
import util from 'util';
import { config } from '../../src/config';

const UserSchema = new mongoose.Schema({
  name: String
})
const User = mongoose.model('user', UserSchema);

const PostSchema = new mongoose.Schema({
  title: String,
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
    required: true,
  }
})
const Post = mongoose.model('post', PostSchema);

mongoose.connect(config.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false });
mongoose.set('debug', true);
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', async () => {
  try {
    // seed
    const users = await User.create([{ name: 'user a' }, { name: 'user b' }]);
    await Post.create([{ title: 'post a', user: users[0]._id }, { title: 'post b', user: users[0]._id }])
    
    // test
    const userIDToBeQuery = users[0]._id;
    const result = await User.aggregate()
      .match({ _id: userIDToBeQuery })
      .lookup({ from: 'posts', localField: '_id', foreignField: 'user', as: 'posts' })

    console.log(util.inspect(result, false, null, true));

  } catch (error) {
    console.log(error);
  } finally {
    await Promise.all([
      db.dropCollection('users'),
      db.dropCollection('posts')
    ]);
    db.close();
  }
})

执行结果:

Mongoose: users.insertOne({ _id: ObjectId("64635f206e50ee5f1b1ece5d"), name: 'user a', __v: 0 }, { session: null })
Mongoose: users.insertOne({ _id: ObjectId("64635f206e50ee5f1b1ece5e"), name: 'user b', __v: 0 }, { session: null })
Mongoose: posts.insertOne({ _id: ObjectId("64635f206e50ee5f1b1ece61"), title: 'post a', user: ObjectId("64635f206e50ee5f1b1ece5d"), __v: 0}, { session: null })
Mongoose: posts.insertOne({ _id: ObjectId("64635f206e50ee5f1b1ece62"), title: 'post b', user: ObjectId("64635f206e50ee5f1b1ece5d"), __v: 0}, { session: null })
Mongoose: users.aggregate([ { '$match': { _id: 64635f206e50ee5f1b1ece5d } }, { '$lookup': { from: 'posts', localField: '_id', foreignField: 'user', as: 'posts' } }], {})
[
  {
    _id: 64635f206e50ee5f1b1ece5d,
    name: 'user a',
    __v: 0,
    posts: [
      {
        _id: 64635f206e50ee5f1b1ece61,
        title: 'post a',
        user: 64635f206e50ee5f1b1ece5d,
        __v: 0
      },
      {
        _id: 64635f206e50ee5f1b1ece62,
        title: 'post b',
        user: 64635f206e50ee5f1b1ece5d,
        __v: 0
      }
    ]
  }
]

软件包版本:"mongoose": "^5.13.17"

相关问题