我有一个post路径,它接收来自express应用程序中PUT请求的数据,该应用程序旨在根据提交的表单输入更新mongoose文档."基本"模型是Profile,我有两个discriminator模型HelperFinder,它们有条件地向Profile模式中添加字段(详见下文).

因此,req.body.profile将包含不同的字段,这取决于它所关联的鉴别器,但始终包含"基本"模型Profile中存在的字段(usernameemailcityaccountType).

在发送PUT请求之前,Profile中的文档示例如下所示:

{ jobTitle: '',
  lastPosition: '',
  email: '',
  city: '',
  accountType: 'helper',
  _id: 5c77883d8db04c921db5f635,
  username: 'here2help',
  __v: 0 }

这在我看来很好,并表明模型是按照我的意愿创建的(基本字段从Profile开始,与Helper模型相关的字段——请参见下面的模型).

我的发帖路由如下:

router.put("/profile/:id", middleware.checkProfileOwnership, function(req, res){

    console.log(req.body.profile);

    Profile.findOneAndUpdate(req.params.id, req.body.profile, function(err, updatedProfile){

        if(err){
            console.log(err.message);
            res.redirect("/profile");
        } else {
            console.log(updatedProfile);
            res.redirect("/profile/" + req.params.id);
        }

    });
});

我从表格(console.log(req.body.profile))中收到的信息是我希望看到的:

{ accountType: 'helper',
  username: 'here2help',
  email: 'helpingU@me.com',
  city: 'New York',
  jobTitle: 'CEO',
  lastPosition: 'sales rep'}

但是,在Profile.findOneAndUpdate()中用req.body.profile更新文档后,我没有看到我返回的文档更新:

console.log(updatedProfile)

{ jobTitle: '',
  lastPosition: '',
  email: 'helpingu@me.com',
  city: 'New York',
  accountType: 'helper',
  _id: 5c77883d8db04c921db5f635,
  username: 'here2help',
  __v: 0 }

因此,我的"基本"模型中定义的字段(即ProfileSchema中定义的字段-见下文)正在更新(例如city),但我的鉴别器中的字段没有更新-见下文.

更新的信息清楚地显示在req中,但没有传播到Profile型号-How can this be?

我也try 过使用findByIdAndUpdate,但我得到了同样的结果.

以下是我定义的模式:

Profile-我的"基本"模式:

var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");

var profileSchema = new mongoose.Schema({ 
    username: String,
    complete: { type: Boolean, default: false },
    email: { type: String, default: "" },
    city: { type: String, default: "" }
}, { discriminatorKey: 'accountType' });

profileSchema.plugin(passportLocalMongoose);

module.exports = mongoose.model("Profile", profileSchema);

Finder

var Profile = require('./profile');

var Finder = Profile.discriminator('finder', new mongoose.Schema({
    position: { type: String, default: "" },
    skills: Array
}));

module.exports = mongoose.model("Finder");

Helper

var Profile = require('./profile');

var Helper = Profile.discriminator('helper', new mongoose.Schema({
    jobTitle: { type: String, default: "" },
    lastPosition: { type: String, default: "" }
}));

module.exports = mongoose.model("Helper");

这是我第一次try 在mongoose中使用discriminators,所以我很可能设置不正确,这是问题的根源.

如果不清楚,请告诉我,或者我需要补充更多信息.

推荐答案

It matters what schema you use to query database

鉴别器基于您使用的对象构建mongo查询.例如,如果使用mongoose.set('debug', true)和run Profile在mongo上启用调试.findOneAndUpdate()您应该看到如下内容:

Mongoose: profiles.findAndModify({
  _id: ObjectId("5c78519e61f4b69da677a87a")
}, [], {
  '$set': {
    email: 'finder@me.com',
    city: 'New York',
    accountType: 'helper',
    username: 'User NAme', __v: 0 } }, { new: true, upsert: false, remove: false, projection: {} })

请注意,它只使用概要模式中定义的字段.

如果使用Helper,您会得到如下结果:

profiles.findAndModify({
  accountType: 'helper',
  _id: ObjectId("5c78519e61f4b69da677a87a")
}, [], {
  '$set': {
    jobTitle: 'CTO',
    email: 'finder@me.com',
    city: 'New York',
    accountType: 'helper ', 
    username: 'User Name', __v: 0 } }, { new: true, upsert: false, remove: false, projection: {} })

请注意,它在筛选条件中添加了鉴别器字段,这是documented:

鉴别器模型是特殊的;它们将鉴别器密钥附加到查询中.换句话说,find()、count()、aggregate()等都足够聪明,可以解释鉴别器.

因此,更新时需要做的是使用discriminator字段,以便在调用update语句时知道要使用哪个模式:

app.put("/profile/:id", function(req, res){
console.log(req.body);

if(ObjectId.isValid(req.params.id)) {

  switch(req.body.accountType) {
    case 'helper':
    schema = Helper;
    break;
    case 'finder':
    schema = Finder;
    break;
    default:
    schema = Profile;
  }      

  schema.findOneAndUpdate({ _id: req.params.id }, { $set : req.body }, { new: true, upsert: false, remove: {}, fields: {} }, function(err, updatedProfile){
      if(err){
          console.log(err);
          res.json(err);
      } else {
          console.log(updatedProfile);
          res.json(updatedProfile);
      }

  });
} else {
  res.json({ error: "Invalid ObjectId"});
} });

请注意,在创建新文档时,上述内容是不必要的,在这种情况下,mongoose可以确定使用哪个鉴别器.

You cannot update discriminator field

上述行为有一个副作用,您无法更新鉴别器字段,因为它找不到记录.在这种情况下,您需要直接访问集合并更新文档,还需要定义属于另一个鉴别器的字段的情况.

db.profile.findOneAndUpdate({ _id: req.params.id }, { $set : req.body }, { new: true, upsert: false, remove: {}, fields: {} }, function(err, updatedProfile){
              if(err) {
                res.json(err);
              } else {
                console.log(updatedProfile);
                res.json(updatedProfile);      
              }
          });

Mongodb相关问答推荐

MongoDB $lookup 查找字段值数组

如何在 kubernetes 中获取分片 mongodb 的备份

定期自动轮换 MongoDb 集合

Mongodb聚合查找异常值

MongoDB 的 Java 语法

无法连接到mongolab主机

mongodump 是否锁定数据库?

如何在 MongoDB 中进行内部连接?

使用 mgo 存储嵌套 struct

MongoDB 1.6.5:如何重命名集合中的字段

如何对连接到 mongo 的方法进行单元测试,而不实际连接到 mongo?

Node + Mongoose:获取最后插入的 ID?

Mongoose.js:嵌套属性的原子更新?

带有部分字符串的mongoose文本搜索

如何在 Rails 中混合使用 mongodb 和传统数据库?

Mongoose / MongoDB 用户通知方案建议

Java + MongoDB:更新文档中的多个字段

RoboMongo:不显示所有文档

MongoDB mongoexport 查询

如何在 Ubuntu 10.04 中使用 --auth 选项重新启动 mongodb?