在 angular-fullstack 中服务器重新启动后,Mongoose populate() 为空

Posted

技术标签:

【中文标题】在 angular-fullstack 中服务器重新启动后,Mongoose populate() 为空【英文标题】:Mongoose populate() is null after server restart in angular-fullstack 【发布时间】:2015-05-21 22:01:52 【问题描述】:

我有引用“所有者”的“视频”猫鼬模式,该模式是对“用户”模式的引用。我正在使用 Angular-Fullstack Yeoman 生成器

video.model.js:

'use strict';
// load the things we need
var mongoose = require('mongoose'), Schema = mongoose.Schema;

var videoSchema = mongoose.Schema(

    type             :  type: String, enum: ['youtube', 'vimeo', 'local'], required: true ,
    owner            :  type: String, ref: 'User', required : true ,
    date             :  type: Date, default: Date.now ,
    name             :  type: String, required: true ,
    sourcemedia      :  type: String, required: true, unique: true

);

// keep our virtual properties when objects are queried
videoSchema.set('toJSON',  virtuals: true );
videoSchema.set('toObject',  virtuals: true );

用户架构(样板 Yeoman angular-fullstack 代码):

'use strict';

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var crypto = require('crypto');
var authTypes = ['github', 'twitter', 'facebook', 'google'];

var UserSchema = new Schema(
  name: String,
  email:  type: String, lowercase: true ,
  role: 
    type: String,
    default: 'user'
  ,
  hashedPassword: String,
  provider: String,
  salt: String,
  facebook: ,
  google: ,
  github: 
);

/**
 * Virtuals
 */
UserSchema
  .virtual('password')
  .set(function(password) 
    this._password = password;
    this.salt = this.makeSalt();
    this.hashedPassword = this.encryptPassword(password);
  )
  .get(function() 
    return this._password;
  );

// Public profile information
UserSchema
  .virtual('profile')
  .get(function() 
    return 
      'name': this.name,
      'role': this.role
    ;
  );

// Non-sensitive info we'll be putting in the token
UserSchema
  .virtual('token')
  .get(function() 
    return 
      '_id': this._id,
      'role': this.role
    ;
  );

/**
 * Validations
 */

// Validate empty email
UserSchema
  .path('email')
  .validate(function(email) 
    if (authTypes.indexOf(this.provider) !== -1) return true;
    return email.length;
  , 'Email cannot be blank');

// Validate empty password
UserSchema
  .path('hashedPassword')
  .validate(function(hashedPassword) 
    if (authTypes.indexOf(this.provider) !== -1) return true;
    return hashedPassword.length;
  , 'Password cannot be blank');

// Validate email is not taken
UserSchema
  .path('email')
  .validate(function(value, respond) 
    var self = this;
    this.constructor.findOne(email: value, function(err, user) 
      if(err) throw err;
      if(user) 
        if(self.id === user.id) return respond(true);
        return respond(false);
      
      respond(true);
    );
, 'The specified email address is already in use.');

var validatePresenceOf = function(value) 
  return value && value.length;
;

/**
 * Pre-save hook
 */
UserSchema
  .pre('save', function(next) 
    if (!this.isNew) return next();

    if (!validatePresenceOf(this.hashedPassword) && authTypes.indexOf(this.provider) === -1)
      next(new Error('Invalid password'));
    else
      next();
  );

/**
 * Methods
 */
UserSchema.methods = 
  /**
   * Authenticate - check if the passwords are the same
   *
   * @param String plainText
   * @return Boolean
   * @api public
   */
  authenticate: function(plainText) 
    return this.encryptPassword(plainText) === this.hashedPassword;
  ,

  /**
   * Make salt
   *
   * @return String
   * @api public
   */
  makeSalt: function() 
    return crypto.randomBytes(16).toString('base64');
  ,

  /**
   * Encrypt password
   *
   * @param String password
   * @return String
   * @api public
   */
  encryptPassword: function(password) 
    if (!password || !this.salt) return '';
    var salt = new Buffer(this.salt, 'base64');
    return crypto.pbkdf2Sync(password, salt, 10000, 64).toString('base64');
  
;

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

我有一个控制器,它具有获取一个视频 (exports.show) 的功能和一个获取多个视频 (exports.index) 的功能,video.controller.js:

'use strict';

var _ = require('lodash');
var Video = require('./video.model');

// Get list of videos
exports.index = function(req, res) 
  Video.find()
  .populate('owner')
  .exec(function (err, videos) 
    console.log("Pulled videos:", videos);
    if(err)  return handleError(res, err); 
    return res.json(200, videos);
  );
;

// Get a single video
exports.show = function(req, res) 
  Video.findById(req.params.id)
  .populate('owner')
  .exec(function (err, video) 
    if(err)  return handleError(res, err); 
    if(!video)  return res.send(404); 
    return res.json(video);
  );
;

如果将视频添加到数据库并在重新启动服务器之前进行查询,则一切都按预期运行。填充功能有效,并且为每个视频填充了一个“所有者”。服务器重新启动后,任何查询的所有所有者都是null,我不知道为什么。如果我查看 Mongo CLI 中的文档,视频有“所有者”,它是用户的字符串“_id”(这是预期的)。

> mongo
MongoDB shell version: 2.4.12
> db.videos.find()
 "owner" : "550a11cb5b3bf655884fad40", "type" : "youtube", "name" : "test", "sourcemedia" : "xxxxxxx", "_id" : ObjectId("550a11d45b3bf655884fad41"), "date" : ISODate("2015-03-18T04:00:00Z"), "__v" : 0 

我尝试使用 Schema.Type.ObjectId 作为视频“所有者”的类型,但得到了相同的结果:

    owner            :  type: Schema.Types.ObjectId, ref: 'User', required : true ,

为什么我的视频的“所有者”属性返回 null?

Mongo 版本:2.4.12 猫鼬版本:3.8.24

【问题讨论】:

您有为用户注册的模型吗? 你可以试试owner : type: Schema.ObjectId, ref: 'User', required : true 【参考方案1】:

哇!使用 angular-fullstack 生成器,每次重新启动服务器时,用户的表都会自动重新播种。我的填充不起作用,因为每次我重新启动时唯一的用户 _id 都会被擦除。

server/config/seed.js 中找到了这条评论,这就是告诉我解决方案的原因...

/**
 * Populate DB with sample data on server start
 * to disable, edit config/environment/index.js, and set `seedDB: false`
 */

为了解决我改变了server/config/environment/development.js,对象(对我来说在第8行)

seedDB: true

seedDB: false

【讨论】:

这似乎是 yeoman angular-fullstack 脚手架中的一个错误,为什么要开发和调试 volatile 用户(默认情况下应该设置为 false)。

以上是关于在 angular-fullstack 中服务器重新启动后,Mongoose populate() 为空的主要内容,如果未能解决你的问题,请参考以下文章

cnsc中服免税店小程序 如何加入购物车

最好用的在线财务软件“秒帐”——中服SaaS超市明星产品推荐

在 angular-fullstack 应用程序中更新后单个帖子不同步

在 Angular-fullstack 中加载 local.env.js

Kubernetes 之limit和request

在 angular-fullstack 中服务器重新启动后,Mongoose populate() 为空