Mongoose 嵌入式文档、方法 "is not a function"

Mongoose Embedded Document, methods "is not a function"

在 Mongoose 中将 EmbeddedDoc 推送到另一个文档的过程中是否有任何原因会剥离该文档的方法?

我使用的脚本曾经有效,所以我不确定发生了什么变化。我知道他们在版本 5 的某个时候引入了 CoreMongooseArray,但我已经恢复到 5.0.7 的早期版本(使用普通数组),问题仍然存在。

我有一个在数组中嵌入购物车项目的购物车架构。购物车项目模式有各种静态和实例方法。在我将文档推入购物车文档之前,这些都是完全可用的。 在那一刻,该函数不再可访问,任何调用结果的错误消息都表明该函数不存在。

基本架构如下:

购物车架构

let mongoose = require('mongoose'),
Schema = mongoose.Schema;
let idvalidator = require('mongoose-id-validator');
let CartItemSchema = require('./CartItem');
let PromotionSchema = require('./Promotion');
let _ = require('lodash');

let CartSchema = new Schema({

   customer_id: {
     type: Schema.Types.ObjectId,
   ref: 'User'
   },
   cartItems: [CartItemSchema],
   customItems: [],
   promotionItems: [{type: PromotionSchema, excludeIndexes: true}],
   quantity: {
        type: Number,
        min: 0,
        required: true,
        default: 0
   },
      subtotal: {
         type: Number,
         min: 0,
         required: true,
         default: 0
      },
      subtotalWithoutTax:{
          type: Number,
          min: 0,
          required: true,
          default: 0
      },
   total: {
    type: Number,
  min: 0,
  required: true,
  default: 0
   },
   totalWithoutTax:{
        type: Number,
        min: 0,
        required: true,
        default: 0
   }
 },
    {
     timestamps: true,
  id: false
    }

);

CartSchema.index({ createdAt: 1 }, { expireAfterSeconds: 604800 });

CartSchema.virtual('discount').get(function(){
    return _.round(this.subtotal - this.total, 2);
});

CartSchema.virtual('tax').get(function(){
    return _.round(this.total - this.totalWithoutTax, 2);
});

CartSchema.set('toObject', {virtuals: true});
CartSchema.set('toJSON', {virtuals: true});

CartSchema.plugin(idvalidator);

module.exports = CartSchema;

购物车项目架构

let mongoose = require('mongoose'),
Schema = mongoose.Schema;
let idvalidator = require('mongoose-id-validator');
let SizeSchema = require('./Size');
let ProductExtraSchema = require('./ProductExtra');

let CartItemSchema = new Schema({
   product_id: {
    type: Schema.Types.ObjectId,
  ref: 'Product',
  required: true
   },
      sku: {
          type: String,
          required: true,
          trim: true,
          lowercase: true
      },
   name: {
  type: String,
  required: true,
  trim: true
   },
   description:  {
  type: String,
  trim: true,
  alias: "desc"
   },
   price: {
    type: Number,
  min: 0,
  required: true,
  default: 0
   },
   priceWithoutTax:{
        type: Number,
        min: 0,
        required: true,
        default: 0
   },
      total: {
          type: Number,
          min: 0,
          required: true,
          default: 0
      },
      totalWithoutTax:{
          type: Number,
          min: 0,
          required: true,
          default: 0
      },
      taxable: {
          type: Boolean,
          required: true,
          default: false
      },
      taxRate: {
          type: Number,
          required: true,
    min: 0,
          default: 0.2
      },
   quantity: {
    type: Number,
  min: 1,
  required: true,
  default: 1
   },
   size: SizeSchema,
      extras: [ProductExtraSchema]
 },
    {
     timestamps: true,
  id: false
    }
);


CartItemSchema.set('toObject', {virtuals: true});
CartItemSchema.set('toJSON', {virtuals: true});

CartItemSchema.plugin(idvalidator);

module.exports = CartItemSchema;

这些在单独的脚本中转换为模型,其中添加了静态模型和实例模型。

如果我随后执行以下操作,这些方法会在推送发生后立即消失:

let CartItem = require('../models/CartItem');
let Cart = require('../models/Cart');

let cartItem = CartItem.hydrate(req.body.cartItem);
let cart = new Cart();
console.log(cartItem.calculateTotals);
cart.cartItems.push(cartItem);
console.log(cart.cartItems[0].calculateTotals);

// Console.logs([Function])
// Console.logs(undefined)

更糟糕的是,我创建了一个非常基本的 mocha 测试,它基本上做了同样的事情并且成功了。那么区别是什么呢? 为什么一个成功而另一个不成功?

describe('test', function(){

    it('should allow childs methods to be accessed', function(){

        let childSchema = new Schema({

                name: String

            },
            {
                timestamps: true,
                id: false
            }

        );
        childSchema.methods.hyper = function(){
            console.log("I've eaten too many sweets")
        };


        let parentSchema = new Schema({

                name: String,
                children: [childSchema],

            },
            {
                timestamps: true,
                id: false
            }

        );

       

        let parent = mongoose.model('Parent', parentSchema);
        let child = mongoose.model('Child', childSchema);

        let c = child.hydrate({name: 'Sarah'});
        let p = new parent({name: 'Joe'});

        p.children.push(c);

        for(let c of p.children){
            c.hyper(); 
            // Successfully logs "I've eaten too many sweets"
        }

        return true;

    });

});

我设法使用以下 schema/model 设置顺序重现此内容:

  1. 创建 CartItemSchema 架构
  2. 创建 CartSchema 架构
  3. 创建 Cart 模型
  4. calculateTotals 方法添加到 CartItemSchema
  5. 创建 CartItem 模型

第 4 步是罪魁祸首:您正在修改模型已经使用的模式(间接地,Cart)。

正确的顺序(或者至少,应该产生最少问题的顺序)应该是:

  1. 创建 CartItemSchema 架构
  2. calculateTotals 方法添加到 CartItemSchema
  3. 创建 CartItem 模型
  4. 创建 CartSchema 架构
  5. 创建 Cart 模型