Add Property to Object that is returned by Sequelize FindOne

26,105

Solution 1

The following works for sequelize v4.

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

Hope this helps. It's a bit late but in case people are still looking for answers.

Solution 2

The Sequelize Model class (of which your cats are instances) has a toJSON() method which res.json will presumably use to serialise your cats. The method returns the result of Model#get() (https://github.com/sequelize/sequelize/blob/95adb78a03c16ebdc1e62e80983d1d6a204eed80/lib/model.js#L3610-L3613), which only uses attributes defined on the model. If you want to be able to set the cats name, but not store names in the DB, you can use a virtual column when defining your cat model:

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

Alternatively, if you don't want to add properties to the model definition:

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

Solution 3

What works for me is to use setDataValue

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

Specs for the function

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

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

Solution 4

It won't let me comment on the correct answer above (https://stackoverflow.com/a/38469390/562683), just wanted to add a use case where this helped me.

I have an existing mysql database that we cannot change the schema of (has to work with the old system and the new system until we can deprecate the old system) but we've layered MonogoDB as well for additional features until we can do a system refactor.

The answer above of the Virtual property helped because i'd basically make a placeholder for the mongo db information (in this case, an object activity log) and add it on the 'findMyObject' service call.

For example:

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

Then in the MyObjectService, findMyObject call:

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

And the resultant JSON looks like:

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

So we were able to extend the object without changing the db, but still have an object in the backend where you can go:

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

Which you wouldn't be able to do if, in the findMyObject function, you either did {raw: true} or result.get({plain: true})

Solution 5

you can use toJSON() to convert Sequelize object into JSON type and then add properties as we do in js

Example :

    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';

    })
Share:
26,105

Related videos on Youtube

Rastalamm
Author by

Rastalamm

Updated on July 09, 2022

Comments

  • Rastalamm
    Rastalamm almost 2 years

    I am trying to add a property to a sequelize instance before passing it back to the client.

    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);
            });
    });
    

    The client only see's {id: 1} and not the newly added key.

    • What is going on here?
    • What type of Object is returned by Sequelize?
    • How can I add new properties to my Cats and send them back?
    • DavidDomain
      DavidDomain almost 8 years
      The returned object is not a plain object, but a modal instance. Take a look at Data retrieval / Finders
    • Rastalamm
      Rastalamm almost 8 years
      I don't want to save any new instances to my DB. Just want res.json(cat) to include any new properties I add to the cat instance.
  • Rastalamm
    Rastalamm almost 8 years
    While this may work, it doesn't seem like this is the best approach.. I am trying to modify an object by assigning it a new key, and passing the modified object, with original key/value pairs + the new key/value pair (instead of the DB instance) to the client.
  • Tom Jardine-McNamara
    Tom Jardine-McNamara almost 8 years
    I'm curious - what's your use case for adding a property after db retrieval? If you feel like adding a virtual property is doing the work in the wrong place because it's too close to the db, then I encourage you to think of Sequelize instances as a handy way of modelling your data objects that just happen to get populated from a database. The only other way I can think of to achieve your goal is to first call cat.toJSON() (which actually returns an object, not a json string) and set your custom property on that.
  • Rastalamm
    Rastalamm almost 8 years
    I think your suggestion of cat.toJSON() is the right fit for me. The use case is the following.. I grab some DB info, run some mathematical functions on the outputs, then return to the client the original numbers as well as some new properties that relate to the outputs from the mathematical functions.
  • Tom Jardine-McNamara
    Tom Jardine-McNamara almost 8 years
    So the cats were a ruse! Glad I could help - mind accepting my answer?
  • Tom Jardine-McNamara
    Tom Jardine-McNamara almost 8 years
    (Also bear in mind what you're describing sounds very much like a computed field. The benefit of using a virtual attribute on the model is that you could define your mathematical transformation in the get() of that attribute so that if you access the model instance from somewhere else you don't need to recalculate the result)
  • Michi-2142
    Michi-2142 almost 5 years
    Awesome. That's absolutely helpful!
  • Martin Naughton
    Martin Naughton almost 4 years
    in sequelize 5 its DataTypes.VIRTUAL sequelize.org/master/manual/getters-setters-virtuals.html
  • milad
    milad almost 4 years
    Thank you, this was the best and simplest answer to this problem