12

In Sequelize >=1.7 we can use promises

Can you explain for me how can i get values from each user in this code:

var User = sequelize.define("user", {
  username: Sequelize.STRING
})


User
  .sync({ force: true })
  .then(function() { return User.create({ username: 'John' }) })
  .then(function(john) { return User.create({ username: 'Jane' }) })
  .then(function(jane) { return User.create({ username: 'Pete' }) })
  .then(function(pete) {
    console.log("we just created 3 users :)")
    console.log("this is pete:")
    console.log(pete.values)

    // what i want:
    console.log("this is jane:")
    console.log(jane.values)

    console.log("this is john:")
    console.log(john.values)
  })

UPD

All values need for set associations with other Model. Actually i need some like this code:

User.hasMany(Group)
Group.hasMany(User)

User
  .sync({ force: true })
  .then(function() { return User.create({ username: 'John' }) })
  .then(function(john) { return User.create({ username: 'Jane' }) })
  .then(function(jane) { return User.create({ username: 'Pete' }) })
  .then(function(pete) { return Group.findOrCreate({id: 1}) })
  .then(function(group) {return group.setUsers([john, jane, pete])})
  .then(function(result) { console.log(result)})
})
dug
  • 2,275
  • 1
  • 18
  • 25
dpolyakov
  • 260
  • 1
  • 3
  • 11
  • I have never heard of sequelize, but `sync({force:true})` does not look like you would need asynchronous promises :-) – Bergi Feb 12 '14 at 01:18
  • Actually `sync({force:true})` can be removed if this method called at project start for example – dpolyakov Feb 12 '14 at 01:36
  • 1
    sync has no relation to promises in this instance; it's a sequelize option to force table creation. – martyman Dec 08 '15 at 20:26

3 Answers3

21

The Bluebird way are the collection helper functions.

If you want to create them in parallel, use map:

User.sync({ force: true })
  .then(function() {
    return Promise.map( ['John', 'Jane', 'Pete'], function(name) {
      return User.create({ username: name });
    })
  }).spread(function(john, jane, pete) {
    console.log("we just created 3 users :)")
    console.log("this is john:")
    console.log(john.values)
    console.log("this is jane:")
    console.log(jane.values)
    console.log("this is pete:")
    console.log(pete.values)
  })

If you need to create them consecutively, just change it to mapSeries (3.0+).

If the array doesn't need to be dynamic, and you simply want to pass a shared value through the promise chain like in your example, have a look at How do I access previous promise results in a .then() chain?.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 4
    Just want to mention that `.sync({ force: true })` will delete all tables in the current database. Be careful! – wprl Jun 27 '14 at 15:31
  • @wprl: I don't know sequelize. Should (can) I omit this call? – Bergi Jun 27 '14 at 15:34
  • @Biergi, check the sync documentation: https://github.com/sequelize/sequelize/wiki/API-Reference-Sequelize#sync You probably still want to sync, but the force option drops the tables each time it's called. Really you want to be using migrations in production, but I haven't gotten to that point in my studies :) – wprl Jul 07 '14 at 16:36
4

Using no additional libraries (and if you need to maintain the order of creates), you can do this by simply creating variable(s) in the enclosing scope which hold the values:

var created = {};
User
  .sync({ force: true })
  .then(function() { return User.create({ username: 'John' }) })
  .then(function(john) { created.john = john; return User.create({ username: 'Jane' }) })
  .then(function(jane) { created.jane = jane; return User.create({ username: 'Pete' }) })
  .then(function(pete) {
    created.pete = pete;

    console.log("we just created 3 users :)")
    console.log("this is pete:")
    console.log(created.pete.values)

    // what i want:
    console.log("this is jane:")
    console.log(created.jane.values)

    console.log("this is john:")
    console.log(created.john.values)
  })

In general though, I would recommend that you lean towards @Bergi's answer which creates a list of Promises and waits for all of the promises to complete.

Edit based on question update:

Using your updated code block and building on @Bergi's suggestion of Promise.map, you can avoid using variables in a higher scope with something like the following:

User.hasMany(Group)
Group.hasMany(User)

User
  .sync({ force: true })
  .then(function() {
    var users = Promise.map( ['John', 'Jane', 'Pete'], function(name) {
      return User.create({ username: name });
    });
    var group = Group.findOrCreate({id: 1});
    return Promise.all([group, users]);
  })
  .spread(function(group, users) {return group.setUsers(users)})
  .then(function(result) { console.log(result)})
})
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
squid314
  • 1,394
  • 8
  • 9
  • Thank you. I added update for my question. Looks like your example of code good for my task – dpolyakov Feb 12 '14 at 01:30
  • You've got the `Promise.all` half-way right :-) `users` does already have the type `Promise<[User]>`, `group` does have the type `Promise` and now we want to get `Promise<(Group, [User])>` - waiting for both all users to be created and the group to be found… – Bergi Feb 12 '14 at 02:23
  • I read the documentation for `Promise.spread` and found that it guaranteed that a call to `Promise.all`. That's why believed I didn't need the `Promise.all` to wrap the returned array. I couldn't find documentation for `Promise.map` so I didn't know that it would give me a `Promise<[User]>` instead of `[Promise]`. That is why my comment existed about the necessity of the `Promise.all` wrapping the users array. I forgot to check if `Promise.all` would recurse into an array it found (as in `[|[Promise]>]`). – squid314 Feb 12 '14 at 04:55
3

Try this...

User
    .sync({ force: true })
    .then(function () {
        return User.create({ username: 'John' });
    })
    .then(function (john) {
        console.log("this is john:");
        console.log(john.values);
        return User.create({ username: 'Jane' });
    })
    .then(function (jane) {
        console.log("this is jane:");
        console.log(jane.values);
        return User.create({ username: 'Pete' });
    })
    .then(function (pete) {
        console.log("we just created 3 users :)");
        console.log("this is pete:");
        console.log(pete.values);
    });
Anthony Chu
  • 37,170
  • 10
  • 81
  • 71