【问题标题】:Mongoose - model methods not found in middlewareMongoose - 在中间件中找不到模型方法
【发布时间】:2018-05-21 08:53:58
【问题描述】:

有可能我只是精疲力尽,但我有以下型号:

用户

const mongoose = require('mongoose');
const validate = require('mongoose-validator');
const Post = require('./post');

let UserSchema = mongoose.Schema({
    firstName: { type: String, required: true },
    lastName: { type: String, required: true },
    email: {
        type: String, required: true, lowercase: true, trim: true, unique: true, index: true,
        validate: [validate({ validator: 'isEmail', message: 'Invalid Email!' })]
    },
    posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }]
})

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

帖子

const _ = require('lodash');
const mongoose = require('mongoose');
const User = require('./user');

let PostSchema = mongoose.Schema({
    user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
    title: { type: String, required: true },
    body: { type: String, require: true }
})

PostSchema.post('save', async function (next) {
    await User.update({ _id: this.user }, { $push: { posts: this._id } })
    return next();
})

module.exports = mongoose.model('Post', PostSchema);

尝试添加新帖子时,帖子保存挂钩运行,但我收到错误 User.update is not a function(findOneAndUpdate、findOne 等也是如此)。

我可以毫无问题地从应用程序的其余部分调用 user.update,所以不确定这里发生了什么。两个模型都在同一个目录中。

【问题讨论】:

  • 小观察,但无论如何都不需要维护数组。您已经在帖子中有用户 id 值,并且可以简单地在 User 上使用“虚拟”(或者只是不要打扰并使用 $lookup always )而不是保留一个数组。另请注意,无论如何您可能应该嵌入 9/10 次。 stackoverflow 上甚至没有一个答案,这会导致 MongoDB 中的嵌入细节实际上违反 16MB BSON 限制。只是出于好奇,如果您删除 async/await 甚至 next 以使其成为串行操作,会发生什么?
  • 使用回调而不是异步的结果相同,你的想法可能更好,但现在这让我很困扰,我需要找出原因:D

标签: node.js mongodb mongoose model


【解决方案1】:

您错过的是 post 中间件的第一个参数是“文档”而不是 next 处理程序:

user.js

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


const userSchema = new Schema({
  firstName: String,
  lastName: String,
  posts: [{ type: Schema.Types.ObjectId, ref: 'Post' }]
});

post.js

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

const User = require('./user');

const postSchema = new Schema({
  user: { type: Schema.Types.ObjectId, ref: 'User' },
  title: String,
  body: String
});

// note that first argument is the "document" as in "post" once it was created
postSchema.post('save', async function(doc, next) {
  await User.update({ _id: doc.user._id },{ $push: { posts: doc._id } });
  next();
});

index.js

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

const User = require('./user');
const Post = require('./post');

const uri = 'mongodb://localhost/posttest';

mongoose.set('debug', true);
mongoose.Promise = global.Promise;

const log = data => console.log(JSON.stringify(data, undefined, 2));

(async function() {

  try {

    const conn = await mongoose.connect(uri);

    await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));

    let user = await User.create({ firstName: 'Ted', lastName: 'Logan' });

    let post = new Post({ user: user._id, title: 'Hi', body: 'Whoa!' });
    post = await post.save();

    mongoose.disconnect();

  } catch(e) {
    console.error(e)
  } finally {
    process.exit()
  }

})()

返回:

Mongoose: users.remove({}, {})
Mongoose: posts.remove({}, {})
Mongoose: users.insertOne({ posts: [], _id: ObjectId("5b0217001b5a55208150cc9b"), firstName: 'Ted', lastName: 'Logan', __v: 0 })
Mongoose: posts.insertOne({ _id: ObjectId("5b0217001b5a55208150cc9c"), user: ObjectId("5b0217001b5a55208150cc9b"), title: 'Hi', body: 'Whoa!', __v: 0 })
Mongoose: users.update({ _id: ObjectId("5b0217001b5a55208150cc9b") }, { '$push': { posts: ObjectId("5b0217001b5a55208150cc9c") } }, {})

显示更新以正确的细节触发。

在良好的设计中,您确实应该避免这种情况,只需从 User 模型中删除 posts 数组。您可以随时使用 virtual 代替:

userSchema.virtual('posts', {
  ref: 'Post',
  localField: '_id',
  foreignField: 'user'
})

或者直接通过$lookup获取数据:

User.aggregate([
   { "$match": { "_id": userId } }
   { "$lookup": {
     "from": Post.collection.name,
     "localField": "_id",
     "foreignField": "user",
     "as": "posts"
   }}
])

在“父”上存储和维护相关 ObjectId 值的数组是一种“反模式”,会导致不必要的开销,例如在两个只需要“一个”的地方写入。

一般来说,您应该选择嵌入“首先”,并且仅在应用程序的使用模式实际需要它时才考虑“引用”。简单地使用并非为此而设计的数据库引擎复制相同模式的 RDBMS 并不是使用它的最佳方式。

【讨论】:

  • 先生,我给你小费!我真的一定已经摆脱了它。
猜你喜欢
  • 2016-07-06
  • 1970-01-01
  • 2016-12-21
  • 2011-11-17
  • 2021-08-01
  • 1970-01-01
  • 2015-03-21
  • 2021-11-29
  • 2016-04-28
相关资源
最近更新 更多