代码之家  ›  专栏  ›  技术社区  ›  Mankind1023

Mongoose-中间件中找不到模型方法

  •  0
  • Mankind1023  · 技术社区  · 8 年前

    有可能我已经精疲力竭了,但我有以下型号:

    用户

    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);
    

    当尝试添加新的日志时,会运行post save hook,但我得到了错误user.update不是一个函数(findoneandupdate、findone等也是如此)。

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

    1 回复  |  直到 8 年前
        1
  •  1
  •   Neil Lunn    8 年前

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

    用户.js

    const { Schema } = mongoose = require('mongoose');
    
    
    const userSchema = new Schema({
      firstName: String,
      lastName: String,
      posts: [{ type: Schema.Types.ObjectId, ref: '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();
    });
    

    索引.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") } }, {})
    

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

    在好的设计中,你真的应该避免这种情况,只需将 posts 数组来自 User 模型。您可以使用 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 值“on the parent”是一种“反模式”,会导致不必要的开销,例如在只需要“one”的两个地方编写。

    此外,一般情况下,您应该选择嵌入“first”,并且仅在应用程序的使用模式实际需要时才考虑“引用”。简单地使用一个数据库引擎复制RDBMS的相同模式并不是利用它的最佳方法。