Get only dataValues from Sequelize ORM
Asked Answered
T

7

91

I'm using the sequelize ORM to fetch data from a PSQL DB. However, when I retrieve something, a whole bunch of data is given. The only data I want is inside 'dataValues'. Of course, I can use object.dataValues. But, is there any other good solutions?

I'm using Sequelize 4.10

Tobytobye answered 23/9, 2017 at 14:20 Comment(0)
T
3

The problem occurs only when I log it using:

console.log(Model.findAll());

If I save it to a variable, I can directly access objects inside without using "dataValues"

Tobytobye answered 3/10, 2017 at 5:53 Comment(1)
This works on JS, but on typescript, the following error will trigger: "error TS2551: Property 'dataValues' does not exist on type 'Model'. Did you mean 'getDataValue'?" For this cases Masoud Tavakkoli answer solve the problem.Philtre
G
154

Yes you can

Model.findAll({
 raw: true,
 //Other parameters
});

would return just the data and not the model instance

Gormless answered 23/9, 2017 at 17:50 Comment(6)
Can I apply that to all queries globally?Tobytobye
You can define it while creating the connection. Something like const sequelize = new Sequelize('connectionUri', { define: { raw: true } });. From the docs hereGormless
Please not this does not work with eager loading nested entities.Iniquitous
To apply to all queries, use var sequelize = new Sequelize('database', 'username', 'password', {query:{raw:true}}) as mentioned in https://mcmap.net/q/160845/-setting-all-queries-to-raw-true-sequelize.Sung
While i'm writing this comment this answer has 55 upvotes, then why it is in last thread ?, it must be on top list. I think Stack Overflow need to change it's algorithm.Wast
You should have some disclaimer while picking rawCounterblast
G
55

Sequelize wraps all it's return values in a virtual object that contains meta data. If you have an object and you just want the undecorated data values, you can unwrap them like so:

Model.findById(1).then(data => {
  console.log(data.get({ plain: true }));
});

Additionally if you just want to print out the object you can use the .toJSON method.

Model.findById(1).then(data => {
  console.log(data.toJSON());
});
Goldeneye answered 6/2, 2018 at 1:44 Comment(2)
I like the data.get answer you gave, it's almost exactly what I want. But do you know if there's a way that one could specify the data.get (or the plain:true, or anything else, really) part in the find's options? E.g. instead of doing what you did, rather something like Model.findOne({ plain:true, ... }).then(...) ? Because the way I see it, if you're only going to filter out the data you want inside the .then(), you might as well save yourself some time and just do data.dataValues instead of data.get(...).Peele
@PrintlnParams See Shivam's answer for details on that, if you want to do that globally see this answer https://mcmap.net/q/160845/-setting-all-queries-to-raw-true-sequelize The method I described is more if you want to use the object for instance methods, etc but you want to encapsulate the implementation details before passing on the values, or for logging. data.dataValues works as well but be careful of mutability, also keep in mind that dataValues is sequelize's internal implementation which may change.Goldeneye
E
21

Finally I found answer after searching a lot. you should do something like this

const users = await db.users.findAll({})
   .map(el => el.get({ plain: true })) // add this line to code

source: github issue

Enslave answered 31/3, 2019 at 11:28 Comment(0)
D
8

This is how I solved mine

    let rows = await database.Book.findAll(options);
    rows = JSON.stringify(rows);
    rows = JSON.parse(rows);

Note that the query has 'include childModel' i could've used 'raw:true' if it just one model. Stringifying the result clears out the '_previousDataValues' e.t.c and give you plain object, now parse the stringified obect back to json. Took me a long time before I could figure this out.

Decimal answered 10/5, 2021 at 15:19 Comment(0)
S
7

To clarify Masoud Tavakkoli's answer (which is not immediately clear on that github answer): using element.get({ plain: true }) returns an array of objects with each attribute key:value pairs.

If you just want an array of one specific attribute's values (eg user ids) instead of objects, you can use something like this:

const users = await User.findAll({
    attributes: ["id"], 
    where: {} // Your filters here
}).map(u => u.get("id")) // [1,2,3]

Nika Kasradze's answer actually achieves the same outcome as a middle-step; using the JSON stringifier generates the same array output. It's possible this is faster than mapping, but I'm not sure.

const users = await User.findAll({
    attributes: ["id"], 
    where: {} // Your filters here
})
const userIds = JSON.stringify(users)) // [1,2,3]
Smashed answered 15/9, 2019 at 3:50 Comment(0)
T
3

The problem occurs only when I log it using:

console.log(Model.findAll());

If I save it to a variable, I can directly access objects inside without using "dataValues"

Tobytobye answered 3/10, 2017 at 5:53 Comment(1)
This works on JS, but on typescript, the following error will trigger: "error TS2551: Property 'dataValues' does not exist on type 'Model'. Did you mean 'getDataValue'?" For this cases Masoud Tavakkoli answer solve the problem.Philtre
R
1

If you don't want to change your finder methods (e.g., some consumers may want the Mongo object and some just the data), you can use .toJSON to get the object from the former.

const query = await myQuery(id);
const record = query.toJSON();
Rahel answered 25/10, 2022 at 18:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.