【问题标题】:Change discriminator value/discriminated type in Mongoose更改 Mongoose 中的鉴别器值/鉴别类型
【发布时间】:2018-02-08 03:35:39
【问题描述】:

我在 Mongoose 中通过两个模型和一个鉴别键表示了一个类层次结构(简单示例):

var options = {discriminatorKey: 'kind'};
var UserSchema = new mongoose.Schema({
    username: {type: String, index: true},
    // some other fields
}, options);

// some  schema methods

var User = mongoose.model('User', UserSchema);
var PowerUserSchema = new mongoose.Schema({
    username: {type: String, index: true},
    // some other fields
    rank: {type: String}
}, options);
var PowerUser = User.discriminator('PowerUser', PowerUserSchema);

到目前为止,这工作正常,但是我遇到了我想将用户“提升”为 PowerUser 的情况。我最初的想法是设置一个用户的“kind”属性并在实例上调用 save() ,希望下次检索到该值时,将返回正确的猫鼬类型:

var user = ... // retrieve user
user.kind = 'PowerUser';
user.save();
user = ... // retrieve user again

这似乎不起作用,因为“种类”值没有保存到实例中。我遇到了this 的建议,不幸的是它也没有更新鉴别器的值。

我现在的问题是:我是否走在正确的轨道上?在这种情况下甚至允许更新鉴别器值,还是我应该以不同的方式更好地构造我的数据(例如,对两者使用单一模式,并使用“类型”条目指定每个实例是什么;这会产生效果对于降级情况,不会丢失任何信息。)

此外,pro(de)moting 用户不应破坏我的数据库中引用 (Power)Users 的所有实例。

谢谢!

【问题讨论】:

  • 为什么不为每个用户添加角色数组,然后根据需要添加和删除它们?
  • 所以你“可以”这样做,但简单地修改数据中的鉴别器值对我来说听起来不是很 OOP。大概PowerUser 具有不同的属性和可能的​​“验证规则”或至少一些区分的“必需”数据。因此,将对象“转换”为PowerUser 然后保存它可能更“正确”。
  • 而且“很遗憾没有更新”,因为您没有阅读所引用的问题。如果您查看帖子,您会看到 {discriminatorKey: 'kind'} 已传递给 Schema 选项。这意味着该键的“默认”值被覆盖。这就是为什么后面的建议是设置.kind 属性。默认情况下,鉴别键的属性被命名为__t。因此user.__t = "PowerUser"。但就像我说的,hacky!
  • 那么,在 JavaScript 中将“User”转换为“PowerUser”,并将其保存回数据库对 mongoose/mongodb 有效吗?我更喜欢这样的解决方案,因为正如您所说,它更像是 OOP。这种方法会破坏对 User 实例的现有引用吗?
  • 引用的方法对我也不起作用。我觉得这是一只猫鼬虫。

标签: node.js mongodb mongoose discriminator


【解决方案1】:

最后我做到了:

var user = ... // retrieve user
var powerUser = PowerUser.hydrate(user.toObject());
powerUser.kind = 'PowerUser';
powerUser.save();
powerUser = ... // retrieve user again

附带说明,将 PowerUser 降级回 User 似乎并没有这样工作。

【讨论】:

  • 它可能无法按您的预期工作。如果userpowerUser有各自的属性,那么转换后user的旧属性仍然设置在新的powerUser中。这一定是一个错误。
  • 看起来它为什么不起作用的问题是当你水合对象时它不会让 mongodb 知道它已经改变了。所以你需要添加 powerUser.markModified('kind')
【解决方案2】:

您是否尝试过在模型上使用 findOneAndUpdate

 User.findOneAndUpdate({_id: _user._id}, {$set: {kind: "PowerUser"}, {new: true}, function (err, doc) {
        should.not.exist(err);
        should.exist(doc.kind);
        doc.kind.should.equal('PowerUser');

        done();
      });

您可以使用这样的静态方法,以防您还需要删除已设置的属性。值 new: true 是获取新修改的文​​件和 strict: false 以便您可以取消设置 UserSchema 上不存在的值

changes = {kind: "PowerUser"}

UserSchema.statics.switchKind = function (id, changes, callBack) {
  const unset = {
    rank: undefined,
    someOtherField: undefined
  };
  return this.findOneAndUpdate({_id: id}, {$set: changes, $unset: unset}, {new: true, strict: false}, callBack);
};

【讨论】:

    猜你喜欢
    • 2017-02-12
    • 1970-01-01
    • 2022-01-16
    • 2018-08-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多