在 Mongoose 中填充嵌套引用仅返回 ID,而不是完整文档

问题描述 投票:0回答:1
// backend\models\Playlist.js
const mongoose = require('mongoose');

const playlistSchema = new mongoose.Schema({
    name: { type: String, required: true },
    videos: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Video' }],
    userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
});

module.exports = mongoose.model('Playlist', playlistSchema);
// backend\models\Video.js
const mongoose = require('mongoose');

const commentSchema = new mongoose.Schema({
  userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
  username: { type: String, required: true },
  comment: { type: String, required: true },
  date: { type: Date, default: Date.now },
});

const videoSchema = new mongoose.Schema({
  title: String,
  description: String,
  url: String,
  uploadDate: {
    type: Date,
    default: Date.now,
  },
  uploader: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
  likes: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
  comments: [commentSchema],
  cloudinary_id: { type: String, required: true },
});

module.exports = mongoose.model('Video', videoSchema);
// backend\models\User.js
const mongoose = require('mongoose');

const bcrypt = require('bcrypt');

const userSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true },
  password: { type: String, required: true },
});

userSchema.pre('save', async function (next) {
  if (this.isModified('password')) {
    this.password = await bcrypt.hash(this.password, 10);
  }
  next();
});

userSchema.methods.comparePassword = function (password) {
  return bcrypt.compare(password, this.password);
};

module.exports = mongoose.model('User', userSchema);

播放列表模态引用了视频模态,视频模态引用了用户模态,但我只收到播放列表模态中存在的视频 ID,而不是整个视频文档。

这就是我使用 API 访问的方式:

router.get('/playlist/:id/videos', authMiddleware, async (req, res) => {
    try {
        const playlist = await Playlist.findById(req.params.id)
            .populate({
                path: 'videos',
                populate: { path: 'uploader' }
            });
        if (playlist.userId.toString() !== req.userData.userId) {
            return res.status(403).json({ message: 'Forbidden' });
        }
        res.json(playlist.videos);
    } catch (err) {
        res.status(500).json({ message: err.message });
    }
});

我尝试注意到我已经在其他 API 中实现了填充并且它工作正常,但在这里不行。

node.js mongodb express mongoose mongoose-populate
1个回答
0
投票

请看下面的代码。这里使用了相同的三个模式定义。然后创建一个测试播放列表。检索代码也与原始问题中使用的代码相同。请查看输出,视频文档现已填充。

请求请密切关注“设置视频参考”行的代码。这可能是根据您的代码进行检查的潜在行。如您所知,这一行设置了视频文档的引用,即播放列表文档和视频文档之间的链接。由于模式定义和 find 语句被发现工作正常,因此这一行将是最有可能审查的一行。

如果事实证明该行在您的代码中也是正确的,请使用一组新文档重复测试 - 创建一个新用户、针对新用户的新视频文档以及针对新视频的新播放列表。

// MongoDB: 7.0.2
// Mongoose : 8.3.2
// Node.js v21.6.0.
// populateissue.mjs

import mongoose, { Schema } from 'mongoose';

main().catch((err) => {
  console.log(err);
});

async function main() {
  await mongoose.connect('mongodb://127.0.0.1:27017/myapp');

  const userSchema = new mongoose.Schema({
    username: { type: String, required: true, unique: true },
    password: { type: String, required: true },
  });

  const Usermodel = mongoose.model('User', userSchema);
  await Usermodel.deleteMany();

  const commentSchema = new mongoose.Schema({
    userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
    username: { type: String, required: true },
    comment: { type: String, required: true },
    date: { type: Date, default: Date.now },
  });

  const videoSchema = new mongoose.Schema({
    title: String,
    description: String,
    url: String,
    uploadDate: {
      type: Date,
      default: Date.now,
    },
    uploader: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
    likes: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
    comments: [commentSchema],
    cloudinary_id: { type: String, required: true },
  });

  const Videomodel = mongoose.model('Video', videoSchema);
  await Videomodel.deleteMany();

  const playlistSchema = new mongoose.Schema({
    name: { type: String, required: true },
    videos: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Video' }],
    userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
  });

  const Playlistmodel = mongoose.model('Playlist', playlistSchema);
  await Playlistmodel.deleteMany();

  const userdoc = new Usermodel({
    username: 'somename',
    password: 'somepassword',
  });

  const videodoc = new Videomodel({
    title: 'someTitle',
    uploader: userdoc._id,
    cloudinary_id: 'someId',
  });

  const playlistdoc = new Playlistmodel({
    name: 'someName',
    videos: videodoc._id,  // setting video reference
    userId: userdoc._id, // kept it the same as uploader since it is a test data
  });

  await userdoc.save();
  await videodoc.save();
  await playlistdoc.save();

  const playlistdocs = await Playlistmodel.findById(playlistdoc._id).populate({
    path: 'videos',
    populate: { path: 'uploader' },
  });

  console.log(playlistdocs);
  console.log(playlistdocs.videos);
}

// output
{
  _id: new ObjectId('6629c3f3450ae04736c1877e'),
  name: 'someName',
  videos: [
    {
      _id: new ObjectId('6629c3f3450ae04736c1877d'),
      title: 'someTitle',
      uploader: [Object],
      likes: [],
      cloudinary_id: 'someId',
      uploadDate: 2024-04-25T02:46:11.929Z,
      comments: [],
      __v: 0
    }
  ],
  userId: new ObjectId('6629c3f3450ae04736c1877c'),
  __v: 0
}
[
  {
    _id: new ObjectId('6629c3f3450ae04736c1877d'),
    title: 'someTitle',
    uploader: {
      _id: new ObjectId('6629c3f3450ae04736c1877c'),
      username: 'somename',
      password: 'somepassword',
      __v: 0
    },
    likes: [],
    cloudinary_id: 'someId',
    uploadDate: 2024-04-25T02:46:11.929Z,
    comments: [],
    __v: 0
  }
]
© www.soinside.com 2019 - 2024. All rights reserved.