Bookshelfjs multiple update data not return promise - javascript

I want to update multiple row to my database. My problem is the promise not return anything. It save successfully but not return anything.
Here sample of my code:
doUpdate: Promise.method(function (data) {
var self = this;
var jsonData = JSON.parse(data);
return Bookshelf.transaction(function (t) {
return _.each(jsonData, function (value, key) {
var queryMatch = {
id: value.id,
id2: value.id2
};
return self.forge(queryMatch)
.fetch({transacting: t})
.then(function (data) {
return data.save({content: value.newValue});
})
.catch(function(error) {
console.log(error)
})
});
});
})
I'm using bluebird promise.

I tried to keep my code as close to yours as possible. I did manage to do what you asked, so take a look if that's something you can use.
doUpdate: Promise.method(function(data) {
var Self = this;
var jsonData = JSON.parse(data);
return bookshelf.transaction(function(t) {
return Promise.each(jsonData, function(value, key) {
var queryMatch = {
id: value.id,
id2: value.id2
};
return new Self(queryMatch).save({
content: value.newValue
}, {
transacting: t,
method: 'update'
});
});
});
})
Let me know if this works for you.

Related

Dynamically call getJSON inside $.when block

Is there some way to rewrite this in less lines of code, by making it dynamic instead of doing multiple similar calls with different indexes?
var input = getInput();
var URL = getEndpointURL();
var results = [];
$.when(
$.getJSON(URL+input[0], function (data,status) {
results[0] = data;
}),
$.getJSON(URL+input[1], function (data,status) {
results[1] = data;
}),
$.getJSON(URL+input[2], function (data,status) {
results[2] = data;
}),
$.getJSON(URL+input[3], function (data,status) {
results[3] = data;
}),
$.getJSON(URL+input[4], function (data,status) {
results[4] = data;
}),
).then(function() {
processResults(results);
});
Assuming input is an array you can map() the array to request promises and use Promise.all() on that array.
const URL = 'https://jsonplaceholder.typicode.com/todos/',
input = [3, 5, 6];
const requestPromises = input.map(function(inp) {
return $.getJSON(URL + inp);
});
Promise.all(requestPromises).then(processResults)
function processResults(data) {
console.log(data)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Turn API call forEach Loop into Promise

I have an API call with a forEach loop which I need to be finished before another function is called. It looks like this:
var getTypes = function() {
var stations = [];
stationservice.getCount('/stations')
.then(succCB, errorCB);
function succCB(data) {
data.data.forEach(function(station) {
stations.push({
id: station._id,
})
})
};
// This should only be called once the forEach Loop is done
processStations(stations);
}
I can't find an understandable example of how I can make sure the processStations() gets called once the loop is done. How can I create a promise for this such that it does what I want to achieve?
As soon as you use promises you have to chain everything that depends on that promise (or use await and async if your environment supports it):
function getTypes() {
return stationservice.getCount('/stations')
.then(function(data) {
var stations = [];
data.data.forEach(function(station) {
stations.push({
id: station._id,
})
})
return stations;
})
.then(processStations);
}
And you should return the Promise chain from your getTypes at least if the getTypes should return something that depends on the stationservice.getCount.
Instead of the forEach you might want to use map because this is what you actually do:
function getTypes() {
return stationservice.getCount('/stations')
.then(function(data) {
return data.data.map(function(station) {
return {
id: station._id,
};
})
})
.then(processStations);
}
If you want a "modern code" answer
var getTypes = function() {
return stationservice.getCount('/stations')
.then(data => data.data.map(({_id: id}) =>({id})))
.then(processStations);
}
this is equal to
var getTypes = function getTypes() {
return stationservice.getCount('/stations').then(function (data) {
return data.data.map(function (_ref) {
return { id: _ref._id };
});
}).then(processStations);
};
Though, since the map isn't asynchronous at all
const getTypes = () => stationservice.getCount('/stations').then(data => processStations(data.data.map(({_id: id}) =>({id}))));
is just fine - and in pre modern browser
var getTypes = function getTypes() {
return stationservice.getCount('/stations').then(function (data) {
return processStations(data.data.map(function (_ref) {
return { id: _ref._id };
}));
});
};
Using Async library
async.forEach(data.data, function (item, callback){
stations.push({
id: item._id,
})
callback();
}, function(err) {
processStations(stations);
});

mongoose sequential promises

I'm trying to do some dynamic queries sequential but for any reason, the next code doesn't fulfil that desired behaviour.
var createEvent = function (user, notification) {
var action, query;
query = { agent: notification.agent, story: notification.story, type: notification.type };
action = { agent: notification.agent, story: notification.story, type: notification.type, ts: notification.ts };
return mongoose.model('Event').findOne(query).exec()
.then(function (response) {
if (response === null) {
return mongoose.model('Event').create(action)
.then(function (response) {
return mongoose.model('User').findByIdAndUpdate(user, { $push: { notifications: { _id: response._id }}});
});
}
return mongoose.model('User').findByIdAndUpdate(user, { $push: { notifications: { _id: notification._id }}}).exec();
});
setTimeout(resolve, 3000);
};
var moveNotifications = function (users) {
var promises = [];
users.map(function (user) {
if (user.notifications.length > 0) {
user.notifications.map(function (notification) {
promises.push(createEvent(user._id, notification));
});
}
});
Promise.each(promises, function (queue_item) {
return queue_item();
});
};
Could someone help me?
As you are calling createEvent inside the nested Array#map loops, you are starting all the queries at once - what you want to do is just get an array of id and notification to later pass to createEvent in Promsise.each
Note: Not sure why you use Array#map, as you never return anything from the map callback - you're basically doing Array#forEach
var moveNotifications = function(users) {
var items = [];
users.forEach(function(user) {
if (user.notifications.length > 0) {
user.notifications.forEach(function(notification) {
items.push({id: user._id, notification: notification});
});
}
});
return Promise.each(events, function(item) {
return createEvent(item._id, item.notification);
});
}
Alternatively, using Array#concat to flatten a 2 level array that is returned by using (nested) Array#map correctly you can achieve the same result
var moveNotifications = function(users) {
return Promise.each([].concat.apply([], users.map(function(user) {
return user.notifications.map(function(notification) {
return {id: user._id, notification: notification};
});
})), function(item) {
return createEvent(item._id, item.notification);
});
}
The above is easily made even more concise using the following ES2015 syntax:
arrow functions =>
spread operator ...
shorthand Object property names {a, b, c}
Destructuring Assignment - Parameter Context Matching ({a, b, c}) =>
var moveNotifications = users =>
Promise.each([].concat(...users.map(user =>
user.notifications.map(notification => ({id: user._id, notification}))
)), ({id, notification}) => createEvent(id, notification)
);
The extreme ES2016 one liner version :p
var moveNotifications = users => Promise.each([].concat(...users.map(user => user.notifications.map(notification => ({id: user._id, notification})))), ({id, notification}) => createEvent(id, notification));

Promise inside promise

I am trying to write this code with Promise. but I don't know how to write promise inside Promise and loop.
I tried to think like this but insertBook function become asynchronously.
How can I get bookId synchronously?
update: function(items, quotationId) {
return new Promise(function(resolve, reject) {
knex.transaction(function (t) {
Promise.bind(result).then(function() {
return process1
}).then(function() {
return process2
}).then(function() {
var promises = items.map(function (item) {
var people = _.pick(item, 'familyName', 'firstNumber', 'tel');
if (item.type === 'book') {
var book = _.pick(item, 'name', 'bookNumber', 'author');
var bookId = insertBook(t, book);
var values = _.merge({}, people, {quotation: quotationId}, {book: bookId});
} else {
var values = _.merge({}, people, {quotation: quotationId});
}
return AModel.validateFor(values);
});
return Promise.all(promises);
}).then(function(items) {
var insertValues = items.map(function (item) {
return People.columnize(item);
});
return knex('people').transacting(t).insert(insertValues);
}).then(function() {
return process5
}).then(function() {
...........
}).then(function() {
t.commit(this);
}).catch(t.rollback);
}).then(function (res) {
resolve(res);
}).catch(function(err) {
reject(err);
});
});
}
function insertBook(t, book){
return Promise.bind(this).then(function () {
return Book.columnizeFor(book);
}).then(function (value) {
return knex('book').transacting(t).insert(value, "id");
});
}
You dont need to get bookid synchronously, you can handle it asynchronously correctly. Also, it is possible you want all book insertions happen sequentially, so I refactored the Promise.all part. (done that just to give you an idea. Promise.all should work fine if insertions in parallel are allowed). Furthermore, I think you shouldn't use Promise.bind. To be honest I dont even know what it does, one thing for sure: it doesn't work with standard promises. So here is an example how I think it should work:
update: function(items) {
return new Promise(function(resolve) {
knex.transaction(function (t) {
resolve(Promise.resolve().then(function() {
return process1;
}).then(function() {
return process2;
}).then(function() {
var q = Promise.resolve(), results = [];
items.forEach(function (item) {
q = q.then(function() {
var book = _.pick(item, 'name', 'bookNumber', 'author');
return insertBook(t, book);
}).then(function(bookId) {
var people = _.pick(item, 'familyName', 'firstNumber', 'tel');
var values = _.merge({}, people, {book: bookId});
return AModel.validateFor(values);
}).then(function(item) {
results.push(item);
});
});
return q.then(function() {
return results;
});
}).then(function(items) {
return process4
}).then(function() {
t.commit(result);
}).catch(function(e) {
t.rollback(e);
throw e;
}));
});
});
}
function insertBook(t, book){
return Promise.resolve().then(function () {
return Book.columnizeFor(book);
}).then(function (value) {
return knex('book').transacting(t).insert(value, "id");
});
}
Assuming that insertBook returns a promise you could do
var people = _.pick(item, 'familyName', 'firstNumber', 'tel');
if (item.type === 'book') {
var book = _.pick(item, 'name', 'bookNumber', 'author');
return insertBook(t, book)
.then(bookId => _.merge({}, people, {quotation: quotationId}, {book: bookId}))
.then(AModel.validateFor)
} else {
return Promise.resolve(_.merge({}, people, {quotation: quotationId}))
.then(AModel.validateFor)
}

not able to pass data to a data object in angularjs

N.B: I'm pretty much new to angularJS programming. What I'm trying to do is, to save info returned by a service to an object. My object looks like this.
var userObject = {
"id": "1",
"firstName": "Amelia",
"lastName": "Earheart"
};
I have a factory that returns data from back end and it looks like this:
.factory('myService', function($http) {
var baseUrl = 'backendservice/';
return {
myInfo:function() {
return $http.get(baseUrl + 'getmyInfo');
}
};
})
And this is how my Controller communicates with the factory service:
.controller('myController', function($routeParams,myService) {
var my = this;
my.basicInfo = function () {
//to get my info
myService.myInfo().success(function(data) {
my.activeUser.myData.id = data.id;
my.activeUser.myData.firstName = data.firstName;
my.activeUser.myData.lastName = data.lastName;
});
};
my.addSomething = function(post) {
var userObject = my.basicInfo();
};
});
and this is how I assign the data to userObject
var userObject = my.basicInfo();
I don't know why it's not working. Factory service runs but the value is not assigned to userObject.
My Controller as whole looks like this:
(function() {
angular
.module('myApp.spa', [])
.factory('myService', function($http) {
var baseUrl = 'backendservice/';
return {
myInfo:function() {
return $http.get(baseUrl + 'getmyInfo');
}
};
})
.controller('myController', function($routeParams,myService) {
var my = this;
my.basicInfo = function () {
//to get my info
myService.myInfo().success(function(data) {
my.activeUser.myData.id = data.id;
my.activeUser.myData.firstName = data.firstName;
my.activeUser.myData.lastName = data.lastName;
});
};
my.addSomething = function(post) {
var userObject = my.basicInfo();
};
});
})();
Your function my.basicInfo() does not return anything so the value of your variable userObject is undefined. Also if you want to use userObject on view expose it on your controller instance as my.userObject.
If you want to assign a value to userObject, do it either within the success callback of my.basicInfo() method or return a promise from the method my.basicInfo() and assign the value in then callback of the promise
Approach 1
my.basicInfo = function () {
//to get my info
var activeUser = {};
return myService.myInfo()
.then(function(response) {
angular.extend(activeUser, response.data);
my.userObject = activeUser;
});
};
Approach 2
my.basicInfo = function () {
//to get my info
var activeUser = {};
return myService.myInfo()
.then(function(data) {
angular.extend(activeUser, response.data);
return activeUser;
});
};
my.addSomething = function(post) {
my.basicInfo()
.then(function (response) {
my.userObject = response;
});
};
Reason is my.basicInfo does not return anything and also from $http.success/failure, you can not return any value.
So in this case, following steps you would have to do:
Define var userObject at the top of your controller so that can be accessible to all the methods.
Assign data to userObject inside success callback of $http
(function() {
angular
.module('myApp.spa', [])
.factory('myService', function($http) {
var baseUrl = 'backendservice/';
return {
myInfo:function() {
return $http.get(baseUrl + 'getmyInfo');
}
};
})
.controller('myController', function($routeParams,myService) {
var my = this;
var userObject;
my.basicInfo = function () {
//to get my info
myService.myInfo().success(function(data) {
my.activeUser.myData.id = data.id;
my.activeUser.myData.firstName = data.firstName;
my.activeUser.myData.lastName = data.lastName;
userObject = data;
});
};
my.addSomething = function(post) {
my.basicInfo();
};
});
})();
.factory('UserInfo', function($resource, apiHost) {
return $resource(apiHost + '/userinfo/:userId');
});
.controller('myController', function($routeParams,UserInfo) {
var vm = this;
// suppose that you have stored the userId somewhere after the login
vm.userObject = {};
var myUserInfo = UserInfo.get({
userId: userId
});
vm.refreshData = function (){
myUserInfo.$promise
.then(function(response) {
vm.userObject = response;
}, function(error) {
// doSomething
});
};
vm.update = function(){
myUserInfo.save(vm.userObject, function() {
// console.log('success');
}, function(error) {
// console.log('error');
});
};
});

Categories

Resources