84

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

Gijo Varghese
  • 11,264
  • 22
  • 73
  • 122

7 Answers7

148

Yes you can

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

would return just the data and not the model instance

Shivam
  • 3,462
  • 1
  • 15
  • 20
  • 4
    Can I apply that to all queries globally? – Gijo Varghese Sep 24 '17 at 00:08
  • 8
    You can define it while creating the connection. Something like `const sequelize = new Sequelize('connectionUri', { define: { raw: true } });`. From the docs [here](http://docs.sequelizejs.com/manual/installation/getting-started.html#application-wide-model-options) – Shivam Oct 03 '17 at 05:05
  • 25
    Please not this does not work with eager loading nested entities. – Sanket Berde Aug 30 '18 at 08:24
  • 9
    To apply to all queries, use `var sequelize = new Sequelize('database', 'username', 'password', {query:{raw:true}})` as mentioned in https://stackoverflow.com/a/26228558/1802726. – Raniere Silva Jun 10 '20 at 13:10
  • 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. – TMA Jun 12 '20 at 12:25
  • 1
    You should have some disclaimer while picking raw – Sulthan Allaudeen Apr 13 '21 at 10:10
52

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());
});
C Deuter
  • 893
  • 1
  • 8
  • 14
  • 1
    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(...)`. – SeriousLee Jan 01 '19 at 10:42
  • 1
    @PrintlnParams See Shivam's answer for details on that, if you want to do that globally see this answer https://stackoverflow.com/a/26228558/3803506 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. – C Deuter Feb 15 '19 at 00:56
19

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

Masoud Tavakkoli
  • 950
  • 13
  • 34
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]
defraggled
  • 1,014
  • 11
  • 13
7

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.

Ahmed Adewale
  • 2,943
  • 23
  • 19
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"

Gijo Varghese
  • 11,264
  • 22
  • 73
  • 122
  • 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. – Yuri Santos Aug 14 '20 at 18:07
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();
occasl
  • 5,303
  • 5
  • 56
  • 81