将属性添加到 Sequelize FindOne 返回的对象

Posted

技术标签:

【中文标题】将属性添加到 Sequelize FindOne 返回的对象【英文标题】:Add Property to Object that is returned by Sequelize FindOne 【发布时间】:2016-11-20 11:14:51 【问题描述】:

我正在尝试将属性添加到续集实例,然后再将其传递回客户端。

router.get('/cats/1', function (req, res) 
    Cat.findOne(where: id: 1)
        .then(function (cat) 
            // cat exists and looks like id: 1
            cat.name = "Lincoln";
            // console.log of cat is id: 1, name: Lincoln
            res.json(cat);
        );
);

客户端只能看到id: 1 而不是新添加的密钥。

这是怎么回事? Sequelize 返回什么类型的对象? 如何向我的 Cats 添加新属性并将它们送回?

【问题讨论】:

返回的对象不是普通对象,而是模态实例。看看Data retrieval / Finders 我不想将任何新实例保存到我的数据库中。只希望res.json(cat) 包含我添加到cat 实例的任何新属性。 【参考方案1】:

以下适用于 sequelize v4。

...
const order = Order.findOne(criteria);
order.setDataValue('additionalProperty', 'some value');
...

希望这会有所帮助。有点晚了,但万一人们还在寻找答案。

【讨论】:

太棒了。这绝对有帮助! 谢谢,这是解决这个问题的最佳和最简单的答案【参考方案2】:

Sequelize Model 类(你的猫是其中的实例)有一个 toJSON() 方法,res.json 可能会使用它来序列化你的猫。该方法返回Model#get() (https://github.com/sequelize/sequelize/blob/95adb78a03c16ebdc1e62e80983d1d6a204eed80/lib/model.js#L3610-L3613) 的结果,它只使用模型上定义的属性。如果您希望能够设置猫的名称,但不将名称存储在数据库中,您可以在定义猫模型时使用虚拟列:

sequelize.define('Cat', 
  // [other columns here...]
  name: Sequelize.VIRTUAL
);

或者,如果您不想在模型定义中添加属性:

cat = cat.toJSON(); // actually returns a plain object, not a JSON string
cat.name = 'Macavity';
res.json(cat);

【讨论】:

虽然这可能有效,但这似乎不是最好的方法。我试图通过为其分配一个新键来修改对象,并使用原始键/传递修改后的对象值对 + 新的键/值对(而不是数据库实例)到客户端。 我很好奇 - 在数据库检索后添加属性的用例是什么?如果您觉得添加虚拟属性在错误的位置完成工作,因为它离数据库太近,那么我鼓励您将 Sequelize 实例视为对恰好从数据库。我能想到的实现目标的唯一其他方法是首先调用cat.toJSON()(它实际上返回一个对象,而不是json字符串)并在其上设置您的自定义属性。 我认为您对cat.toJSON() 的建议非常适合我。用例如下。我获取一些数据库信息,在输出上运行一些数学函数,然后将原始数字以及与数学函数的输出相关的一些新属性返回给客户端。 所以猫是个诡计!很高兴我能帮忙 - 介意接受我的回答吗? (还请记住,您所描述的内容听起来很像计算域。在模型上使用虚拟属性的好处是您可以在 get() 的该属性,因此如果您从其他地方访问模型实例,则无需重新计算结果)【参考方案3】:

对我有用的是使用setDataValue

router.get('/cats/1', function (req, res) 
    Cat.findOne(where: id: 1)
        .then(function (cat) 
            cat.setDataValue("name", "Lincoln");
            res.json(cat);
        );
);

函数规格

public setDataValue(key: string, value: any)

Update the underlying data value

Params:

Name    Type    Attribute   Description
key     string              key to set in instance data store   
value   any                 new value for given key

来源:https://sequelize.org/master/class/lib/model.js~Model.html#instance-method-setDataValue

【讨论】:

【参考方案4】:

它不会让我评论上面的正确答案 (https://***.com/a/38469390/562683),只是想添加一个对我有帮助的用例。

我有一个现有的 mysql 数据库,我们无法更改其架构(必须与旧系统和新系统一起使用,直到我们可以弃用旧系统),但我们也分层了 MonogoDB 以获得其他功能,直到我们可以进行系统重构。

Virtual 属性的上述答案有所帮助,因为我基本上会为 mongo db 信息(在本例中为对象活动日志)创建一个占位符并将其添加到“findMyObject”服务调用中。

例如:

const model = sequelize.define('myobj', 
  id: 
    type: Sequelize.INTEGER,
    autoIncrement: true,
    primaryKey: true,
    field: 'eventId',
  ,
  name:  type: Sequelize.STRING, allowNull: false ,
  history: Sequelize.VIRTUAL,
  ...

然后在MyObjectService中,findMyObject调用:

...
const result = yield MyObject.findOne(query);
result.history = yield getMyObjectHistoryArray(id);
return result;

生成的 JSON 如下所示:


  "id": 1,
  "name": "My Name",
  "history": [ 
    ...,
    ...,
  ]

所以我们能够在不更改数据库的情况下扩展对象,但在后端仍然有一个对象可以访问:

let obj = yield findMyObject(id);
obj.name = "New Name";
return yield obj.save();  

如果您在 findMyObject 函数中执行了 raw: trueresult.get(plain: true),您将无法做到这一点

【讨论】:

【参考方案5】:

你可以使用 toJSON() 将 Sequelize 对象转换为 JSON 类型,然后像我们在 js 中一样添加属性

例子:

    UserModel.findById(req.params.id)
     .then(function (userIns) 

        // here userIns is Sequelize Object 
        // and data is Json Object

        let data = userIns.toJSON();
        data['displayName'] = 'John';

    )

【讨论】:

以上是关于将属性添加到 Sequelize FindOne 返回的对象的主要内容,如果未能解决你的问题,请参考以下文章

Sequelize 默认方法 findOne bug

[usedIf在数据库中时,sequelize findOne找不到用户标识

在使用急切加载的 findOne Sequelize 方法期间,Nodejs 堆内存不足

Sequelize 不会将值插入到新添加的列中

如何将查询逻辑添加到基于 graphql-sequelize 的设置?

Sequelize 中的 WhereHas 方法