Sequelize - Bulk create from array - javascript

I have an array of items and need to create them to DB.
I need to check each insert if it success so insert to new array (results) the item + success = true as a json.
If not succeed to create - insert to the same array before (results) the item + success = false.
Here's the code:
create_cards: function (filter_id, is_filter, cards) {
var result = [];
var curr_card = null;
for (var card in cards) {
curr_card = this.create( {
filter_id: filter_id,
template: card.template,
state: card.state,
question_id: card.question_id || -1,
answers: card.answers || -1,
description: card.description || -1,
correct_answer: card.correct_answer || -1
}).then(function(card) {
result.push({card: JSON.stringify(card.dataValues), success: true})
},function(err) {
result.push({card: card.dataValues, success: false})
});
}
return results;
}
Now, 2 questions:
There is 'return result' after the loop is over, but i get empty array..
How should i do bulk create AND after each create, to make sure if the creation succeed?
How should i get the card in the error function? i get only 'err' as variable to the reject function.
Thanks!

create_cards: function(filter_id, is_filter, cards) {
var result = [];
var promises = cards.map(function(card) {
return this.create({
filter_id: filter_id,
template: card.template,
state: card.state,
question_id: card.question_id || -1,
answers: card.answers || -1,
description: card.description || -1,
correct_answer: card.correct_answer || -1
})
.then(function() {
result.push({
card: card,
success: true
});
})
.catch(function(err) {
result.push({
card: card,
success: false
});
return Promise.resolve();
});
});
return Promise.all(promises)
.then(function() {
return Promise.resolve(result);
});
}

Related

for loop logic fail to detect if item exists in array (javascript)

I am looking to check if a product id already exists in memory so I only update the quantity of it, my data is an array looking like [{ id: data.id, price: data.price, qty: 1 }]
My code is this function
storeProduct = async (data) => {
this.setState({ found: null })
try {
const value = await AsyncStorage.getItem('cart')
if (value !== null) {
var products = JSON.parse(value)
for (let x in products) {
if (products[x].id === data.id) {
this.setState({ found: true })
} else {
this.setState({ found: false })
}
}
} else {
await AsyncStorage.setItem(
'cart',
JSON.stringify([{ id: data.id, price: data.price, qty: 1 }])
)
}
if (this.state.found === false) {
var obj = { id: data.id, price: data.price, qty: 1 }
await AsyncStorage.setItem('cart', JSON.stringify([...JSON.parse(value), obj]))
}
} catch (error) {
this.setState({ error: error })
}
}
it does work but only when testing on same product, when I click on another product and then go back to first one it concat that id to the array and I get 2 similar ids. It's weird so I am not sure what logic I should use, I was inspired by the example below using redux:
if(action.type === ADD_TO_CART){
let addedItem = state.items.find(item=> item.id === action.id)
//check if the action id exists in the addedItems
let existed_item= state.addedItems.find(item=> action.id === item.id)
if(existed_item)
{
addedItem.quantity += 1
return{
...state,
total: state.total + addedItem.price
}
}
else{
addedItem.quantity = 1;
//calculating the total
let newTotal = state.total + addedItem.price
return{
...state,
addedItems: [...state.addedItems, addedItem],
total : newTotal
}
}
}
I think problem might be inside your for loop, its getting executed for multiple items.
For example -
let products = [{ id: "id", price: "price", qty: 1 },{ id: "id2", price: "price2", qty: 12 }]
for (let x in products) {
if (products[x].id === data.id) {
this.setState({ found: true })
} else {
this.setState({ found: false })
}
}
For first product, it will set found equal to true, and again for the second iteration, it will go into else and set found equal to false. I think maybe because of this you are getting a duplicate product.
Instead of for loop to check if element exists or not you can use findIndex method of array -
let index = products.findIndex((element)=> element.id === data.id)
if(index !== -1)
{
this.setState({ found: true })
}else{
this.setState({ found: false })
}
Reference for findindex - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
im not familiar with react, but normally a line like this: for (let x in products), will bring back a product for x, not an index. you are treating x like an index. is that part of the problem?

filter array to product check in record for events

I have an activity feed, it contains a number of different types of activity for our site.
one type of activity is checkin. which logs when a user checks in and checkouts of a site.
The record entries look like so
Entryable_id | Entry_type | Action | timestamp
1 Ticket Update 12:01
3 Ticket New 12:07
4 CheckIn ClockedIn 14:30
4 CheckIn ClockedOut 17:30
What I want to do is create an array with entries in it like so
Entryable_id | ClockedIn| ClockedOut
4 14:30 17:30
so far what I have is
{
let staffCheckins = []
let checkinRecord = []
if (this.DiaryStore.entries.length) {
this.DiaryStore.entries.forEach(function(val) {
if (val.entryable_type === 'CheckIn') {
staffCheckins.push(val);
return val
}
})
}
staffCheckins.forEach(function(val) {
if (val.action === "ClockedIn") {
checkinRecord[val.entryable_id] = {
clockedIn: val.created_at,
user: val.user
}
}
if (val.action === "ClockedOut") {
checkinRecord[val.entryable_id] = {
clockedOut: val.created_at
}
}
})
console.log(completeCheckin)
},
which gives
1: clockedIn: "2019-07-22T10:26:45.000000Z",
2: clockedIn: "2019-07-22T12:38:02.000000Z"
so I assume that it is not appending to the key when i do
checkinRecord[val.entryable_id] = {clockedOut: val.created_at}
On top of that this all feels like a mess. is there a better way to filter and get what I need?
Thanks
You need to merge attribute, instead of assign to new object
staffCheckins.forEach(function(val) {
if (!checkinRecord[val.entryable_id]) {
checkinRecord[val.entryable_id] = {}
}
if (val.action === "ClockedIn") {
checkinRecord[val.entryable_id] = {
...checkinRecord[val.entryable_id],
clockedIn: val.created_at,
user: val.user
}
} else (val.action === "ClockedOut") {
checkinRecord[val.entryable_id] = {
...checkinRecord[val.entryable_id],
clockedOut: val.created_at
}
}
}
so I haven't gotten to test it because I'm out and about but you could try something like this. If they object entryable_id doesnt exist in the current object in the array, then it will create a new object with the members, otherwise it will find the object and update the fields
{
let staffCheckins = [];
let checkinRecord = [];
if (this.DiaryStore.entries.length) {
staffCheckins = this.DiaryStore.filter(val => val.entryable_type.toLowerCase() === 'checkin');
}
staffCheckins.forEach(function(val, i) {
let { action, entryable_id, created_at, user } = val;
if (!entryable_id in checkinRecord[i]) {
checkinRecord[i] = {
clockedIn: created_at,
clockedOut: created_at,
user
}
}
if (action.toLowerCase() === 'clockedin') {
checkinRecord[i] = {
...checkinRecord[i],
clockedIn: created_at,
user
}
} else if (action.toLowerCase() === 'clockedout') {
checkinRecord[i] = {
...checkinRecord[i],
clockedOut: created_at
}
}
});
}
apologies if I understood wrong but I'm also no currently at my actual computer to test any of it
You could do this whole operation in a filter reduce combination and create a groupBy object using the Entryable_id as keys.
Once loop completes get values array of that object
const checkinGroup = data.filter(({Entry_type}) => Entry_type === 'CheckIn')
.reduce((a, c)=>{
let {Entryable_id:id, Action, timestamp} = c;
a[id] = a[id] || {Entryable_id: id, ClockedIn: null, ClockedOut: null};
a[id][Action] = timestamp;
return a;
},{});
const res = Object.values(checkinGroup)
console.log(res)
<script>
const data = [{
Entryable_id: 1,
Entry_type: 'Ticket',
Action: 'Update',
timestamp: '12:01'
},
{
Entryable_id: 3,
Entry_type: 'Ticket',
Action: 'New',
timestamp: '12:07'
},
{
Entryable_id: 4,
Entry_type: 'CheckIn',
Action: 'ClockedIn',
timestamp: '14:30'
},
{
Entryable_id: 4,
Entry_type: 'CheckIn',
Action: 'ClockedOut',
timestamp: '17:30'
}
]
</script>

Semantic UI - Search API: how I can highlight certain characters that match the query?

I have a problem when I want to highlight certain characters that match the query in search module.
an example is like this forum: https://forums.meteor.com
Previously, I already asked this issue at https://github.com/Semantic-Org/Semantic-UI/issues/4930#issuecomment-275011130, but until now not been resolved.
here is my current demo: https://jsfiddle.net/agaust/5854gae9/4/
$(document).ready(function() {
$.fn.api.settings.api = {
'search': 'https://gist.githubusercontent.com/agusmakmun/e258a3243367105c32919c083eb577fe/raw/8b0038b0141f5813c03baece0b2730e17216f8c9/result-data.json?q={query}'
};
$('.ui.search.quick-search').search({
type : 'category',
minCharacters : 1, // just under devel to make it easy
apiSettings : {
action: 'search',
onResponse: function(searchApiResponse) {
var response = {
results : {},
//action : searchApiResponse.action // dict action
};
// translate `searchApiResponse` response to work with search
var numbThreads = 0, numbUsers = 0;
$.each(searchApiResponse.items, function(index, item) {
var
model = item.model || 'Unknown',
maxResults = 6,
maxItems = maxResults/2 // max results per-Category
;
if(index >= maxResults) {
return false;
}
// create new model category
if(response.results[model] === undefined) {
response.results[model] = {
name : model,
results : []
};
}
if(item.model === 'Threads') {
if ((numbThreads < maxItems) || (numbUsers < numbThreads)) {
response.results[model].results.push({
title: item.title,
description: item.description,
url: item.url
});
}
numbThreads++;
}else if (item.model === 'Users') {
if ((numbUsers < maxItems) || (numbThreads < numbUsers)) {
response.results[model].results.push({
title: item.username,
description: item.username,
url: item.profile_url,
image: item.gravatar_url,
price: item.total_threads
});
}
numbUsers++;
}
});
// only showing the bottom action button if under limited
if (searchApiResponse.limited_items) {
response["action"] = searchApiResponse.action;
}
console.log(response);
return response;
}
}
});
});
any help would be apreciated.. :)

Javascript function to return Elasticsearch results

I'm trying to write a JavaScript function that returns results of an Elasticsearch v5 query. I can't figure out where and how to include 'return' in this code. With the following, segmentSearch(id) returns a Promise object,{_45: 0, _81: 0, _65: null, _54: null}.
_65 holds an array of the correct hits, but I can't figure out how to parse it. The console.log(hits) produces that same array, but how can I return it from the function?
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
host: 'localhost:9200',
log: 'trace'
});
segmentSearch = function(id){
var searchParams = {
index: 'myIndex',
type: 'segment',
body: {
query: {
nested : {
path : "properties",
query : {
match : {"properties.source" : id }
},
inner_hits : {}
}
}
}
}
return client.search(searchParams).then(function (resp) {
var hits = resp.hits.hits;
console.log('hits: ',hits)
return hits;
}, function (err) {
console.trace(err.message);
});
}
I would instanitate a new array outside of your client.search function in global scope and array.push your 'hits' Then access your newly filled array.
let newArr = [];
client.search(searchParams).then(function (resp) {
for(let i = 0; i < resp.hits.hits.length; i++){
newArr.push(resp.hits.hits[i]);
}
console.log('hits: ',newArr)
return newArr;
}, function (err) {
console.trace(err.message);
});
First of all, elasticsearch js client is working with Promise ( I think using callback is also possible).
Using Promise is a good way to handle asynchronous computation.
In your question, you have already done something with a promise:
var search = function(id)
{
var searchParams = { /** What your search is **/}
return client.search(searchParams)
}
This call is returning a Promise.
If we consider handleResponse as the function in your then
var handleResponse = function(resp)
{
var hits = resp.hits.hits;
console.log('hits: ',hits)
return hits; //You could send back result here if using node
}
In your code, handleResponse is called once the promise is fullfield. And in that code you are processing data. Don't forget you are in asynchronious, you need to keep working with promise to handle hits.
By the way, in your question, what you have done by using "then" is chaining Promise. It is normal to have Promise.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
Promise.prototype.then is returning a Promise.
var segmentSearch = function ( id )
{
return search
.then( handleResponse //here you got your hit )
.then( function ( hits )
{
console.log(hits) //and here you have done something with hits from search.
})
}
I neglected to post my fix, sorry about that. The sequence is to create searchParams, perform client.search(searchParams) which returns a Promise of hits, then process those hits:
segmentSearch = function(obj){
// retrieve all segments associated with a place,
// populate results <div>
let html = ''
var plKeys = Object.keys(obj)
var relevantProjects = []
for(let i = 0; i < plKeys.length; i++){
relevantProjects.push(obj[plKeys[i]][0])
var searchParams = {
index: 'myIndex',
type: 'segment',
body: {
query: {
nested : {
path : "properties",
query : {
match : {"properties.source" : id }
},
inner_hits : {}
}
}
}
}
client.search(searchParams).then(function (resp) {
return Promise.all(resp.hits.hits)
}).then(function(hitsArray){
...write html to a <div> using hits results
}
}

Sails populate field does not return with correct results

I have a User model like this:
/**
* User.js
*
* #description :: TODO: You might write a short summary of how this model works and what it represents here.
* #docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
firstName: 'string',
lastName: 'string',
fullName: {
type: 'string',
index: true
},
loginMethod: 'integer',
emailAddress: {
type: 'string',
unique: true
},
password: 'string',
friends: {
collection: 'User'
},
tallys: {
collection: 'Tally',
via: 'associatedUser'
},
friendsTallys: {
collection: 'Tally',
via: 'invitedUsers'
},
toJson: function() {
var obj = this.toObject();
delete obj.friends;
delete obj.tallys;
delete obj.friendsTallys;
return obj;
}
},
beforeCreate: function(values, cb) {
// Set the full name property using the first name and the last name
values.fullName = values.firstName + " " + values.lastName;
cb();
}
};
I have a Tally model like this:
/**
* Tally.js
*
* #description :: TODO: You might write a short summary of how this model works and what it represents here.
* #docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
associatedUser: {
model: 'User'
},
type: 'integer',
yesThisCount: 'integer',
noThatCount: 'integer',
caption: 'string',
photos: {
collection: 'Photo'
},
invitedUsers: {
collection: 'User'
}
}
};
I have a bootstrap js file like this:
/**
* Bootstrap
* (sails.config.bootstrap)
*
* An asynchronous bootstrap function that runs before your Sails app gets lifted.
* This gives you an opportunity to set up your data model, run jobs, or perform some special logic.
*
* For more information on bootstrapping your app, check out:
* http://sailsjs.org/#/documentation/reference/sails.config/sails.config.bootstrap.html
*/
var async = require('async');
module.exports.bootstrap = function(cb) {
// It's very important to trigger this callback method when you are finished
// with the bootstrap! (otherwise your server will never lift, since it's waiting on the bootstrap)
/**
* Make some fake users for testing
* These will not be used for logging in.
* This is just to check addFriend and searching
*/
var asyncCreateUsers = [];
var asyncCreatePhotos = [];
var asyncCreateTallys = [];
var usersJS = [];
var usersSails = [];
var talliesJS = [];
var yesNoPhotoSails;
var thisPhotoSails;
var thatPhotoSails;
// create the user javascript objects
for (idx = 0; idx < 5; idx ++) {
usersJS.push({
firstName: 'Test0' + idx + '_first',
lastName: 'Test0' + idx + '_last',
emailAddress: 'test0' + idx + '#test.com',
password: 'testing',
loginMethod: 0
});
}
// push each thing into the asyncTasks array
_.each(usersJS, function(user) {
asyncCreateUsers.push(function(callback){
User.create(user).exec(function(error, user){
if (error) {
sails.log.error("whoops, user not created");
} else {
sails.log.info("user created");
usersSails.push(user);
}
callback();
}
);
});
});
async.parallel(asyncCreateUsers, function() {
// Finish created users in sails
sails.log.info('created users, now create photos');
// Make them all friends.
createPhotosAsynchronously();
});
function createPhotosAsynchronously() {
// Create my photos
var yesNoPhoto = {
path: 'https://upload.wikimedia.org/wikipedia/en/6/6f/Yoda_Attack_of_the_Clones.png'
};
var thisPhoto = {
path: 'http://static.comicvine.com/uploads/original/11118/111184078/4610796-0849145928-4-Ana.jpg'
};
var thatPhoto = {
path: 'http://s3.amazonaws.com/rapgenius/1345598281_Episode_4_Luke_Skywalker_1.jpg'
};
asyncCreatePhotos.push(function(callback){
Photo.create(yesNoPhoto).exec(function(error, photo){
if (error) {
sails.log.error('whoops, yesno photo not created');
} else {
yesNoPhotoSails = photo;
}
callback();
});
});
asyncCreatePhotos.push(function(callback){
Photo.create(thisPhoto).exec(function(error, photo){
if (error) {
sails.log.error('whoops, this photo not created');
} else {
thisPhotoSails = photo;
}
callback();
});
});
asyncCreatePhotos.push(function(callback){
Photo.create(thatPhoto).exec(function(error, photo){
if (error) {
sails.log.error('whoops, that photo not created');
} else {
thatPhotoSails = photo;
}
callback();
});
});
async.parallel(asyncCreatePhotos, function(){
// Finished creating photos, create tallys now.
sails.log.info('created photos, now create tallys');
createTallysAsynchronously();
});
}
function createTallysAsynchronously() {
var userIds = _.pluck(usersSails.slice(), 'id');
// create the tallies javascript objects
for (idx = 0; idx < usersSails.length; idx ++) {
talliesJS.push({
associatedUser: usersSails[idx],
type: 0,
yesThisCount: 0,
noThatCount: 0,
caption: 'YesNo',
photos: [yesNoPhotoSails]
});
talliesJS.push({
associatedUser: usersSails[idx],
type: 1,
yesThisCount: 0,
noThatCount: 0,
caption: 'ThisThat',
photos: [thisPhotoSails, thatPhotoSails]
});
}
_.each(talliesJS, function(tally) {
asyncCreateTallys.push(function(callback){
Tally.create(tally).exec(function(error, createdTally){
if (error) {
sails.log.error("tally did not create");
} else {
Tally.findOne({id: createdTally.id}).populate('invitedUsers').exec(
function(e,r){
var associatedUser = r.associatedUser;
sails.log.info('associated User: ' + associatedUser);
var ids = _.reject(userIds, function(id) {return id == associatedUser});
_.each(ids, function(id){
r.invitedUsers.add(id);
r.save(function(err){sails.log.info('saved after adding invitedUser: ' + id)});
});
callback();
});
}
});
});
});
async.parallel(asyncCreateTallys, function() {
// FIN
sails.log.info('created tallys, finished');
cb();
});
}
};
I have a login method which looks like this:
var loginUserFunction = function(){
User.findOne({emailAddress: user.emailAddress})
.populate("tallys")
.populate('friendsTallys')
.populate('friends')
.exec(function(err, found) {
if(err) {
sails.log.error("There was an error looking for the user: " + JSON.stringify(err));
return res.serverError({error: sails.config.errors.SERVER_ERROR});
}
if(found == null) {
sails.log.info("Could not find user with email address: " + user.emailAddress);
return res.badRequest({error: sails.config.errors.INVALID_EMAIL});
}
if(found && found.loginMethod != user.loginMethod)
{
sails.log.info("The user tried to login using the wrong method!");
return res.badRequest({error: sails.config.errors.INVALID_LOGIN_METHOD});
}
var friends = found.friends;
var friendsTallysIds = _.pluck(found.friendsTallys, 'id');
// We populated tallys and friendsTallys but we need to get the fields in those tallys to be populated so we have to query directly for the Tallys
Tally.find(_.pluck(found.tallys, 'id'))
.populate('associatedUser')
.populate('invitedUsers')
.populate('photos')
.exec(function(err, tallys) {
if(err){
sails.log.error("There was an error getting the tallys for the user: " + JSON.stringify(err));
return res.serverError({error: sails.config.errors.SERVER_ERROR});
}
if(tallys == null)
{
tallys = [];
}
Tally.find(_.pluck(found.friendsTallys, 'id'))
.populate('associatedUser')
.populate('invitedUsers')
.populate('photos')
.exec(function(err, friendsTallys) {
if(err){
sails.log.error("There was an error getting the friends' tallys for the user: " + JSON.stringify(err));
return res.serverError({error: sails.config.errors.SERVER_ERROR});
}
if(friendsTallys == null)
{
friendsTallys = [];
}
sails.log.info("The user was found: " + user.emailAddress);
// Generate an auth token for the user
var userAuthToken = EncryptionService.generateUserAuthToken(found);
// Set the token in the response headers
res.set('userAuthToken', userAuthToken);
// Remove the tallys, friendTallys, friends from the found object
// Subscribe the user to this own model
User.subscribe(req.socket, found);
// Subscribe to own tallys
Tally.subscribe(req.socket, tallys);
// Subscribe to Friends' Tallys
Tally.subscribe(req.socket, friendsTallys);
// Send the response
res.json({
user: found,
tallys: tallys,
friendsTallys: friendsTallys,
friends: friends
});
});
});
});
}
My problem is that the friendsTallys field in my user objects is showing only 2 tallys when in fact there should be 8 tallys because I create 2 tallys for each user and then invite all the other users for each tally. Furthermore, those 2 tallys in the friendsTalls is the same tallys in the Tallys field. This is a view of my breakpoint:
Thanks for the help. If you need more info/code/context just let me know.

Categories

Resources