Sails.js Waterline UPDATE: How to handle multiple updates - javascript

I have an array of objects that I want to update, thus a multiple update. I am looking for the best way to implement this. Each object includes the same properties, but the properties for each object have different values.
Do I implement something like this?
var people = [
{'firstName': 'Brian', 'clockedIn': '2016-4-12', 'type': 'developer'},
{'firstName': 'Taylor', 'clockedIn': '2016-4-14', 'type': 'developer'},
{'firstName': 'Jake', 'clockedIn': '2016-4-14', 'type': 'manager'}
];
PersonModel.update({'type': 'developer'}, people, function(err, records) {
// ...
// ...
});
If I do something like the previous code, what exactly does it do? Does it automatically try to match the primary key of each record in the people array, update any of the properties that are listed, and then pass the records that were updated into the callback function?
I noticed in the Sails.js documentation here that the second argument for the update function can be an object OR an array, I am just unclear if I can use it like this. The documentation is unclear.
If I cannot use it like this and I wanted to try an iterative or recursive approach, how would you suggest I implement it?

What is your adapter ?
I had to do this with MySQL, I make the query my self, and then call PersonModel.query(myQuery)
I follow this answer to make it (example with two field) :
values = [
{
id: 1,
param_1: 'NewValueParam1',
param_2: 'NewValueParam2'
},
{
id: 2,
param_1: 'AnotherNewValueParam1',
param_2: 'AnotherNewValueParam2'
}
];
function multiValuesUpdate(values) {
var request = "UPDATE MyTable SET ";
var part_param_1 = "`param_1` = (CASE `id` ";
var part_param_2 = "`param_2` = (CASE `id` ";
var part_ids = "WHERE `id` IN (";
_.forEach(values, function (v) {
part_param_1 += "WHEN '" + v.id + "' THEN '" + v.param_1 + "' ";
part_param_2 += "WHEN '" + v.id + "' THEN '" + v.param_2 + "' ";
part_ids += v.id + ",";
});
part_param_1 += "ELSE `param_1` END), "; // Be careful with the comma !
part_param_2 += "ELSE `param_2` END) ";
part_ids = part_ids.slice(0, -1) + ");"; // Remove the last "," and add ");"
request += part_param_1 + part_param_2 + part_ids;
return request;
}
console.log(multiValuesUpdate(values));
Output :
"UPDATE MyTable
SET `param_1` = (
CASE `id`
WHEN '1' THEN 'NewValueParam1'
WHEN '2' THEN 'AnotherNewValueParam1'
ELSE `param_1`
END),
`param_2` = (
CASE `id`
WHEN '1' THEN 'NewValueParam2'
WHEN '2' THEN 'AnotherNewValueParam2'
ELSE `param_2`
END)
WHERE `id` IN (1,2);"

Related

Loop after Grouped JSON properties

https://jsfiddle.net/MauroBros/f1j0qepm/28/#&togetherjs=qedN5gf7SF
I have a JSON object as follows:
var values = [
{"aname":"account1", "pname":"pname1", "vname":"vname1", "vid":"xxx"},
{"aname":"account2", "pname":"pname2", "vname":"vname2", "vid":"xxx"},
{"aname":"account2", "pname":"pname2", "vname":"vname3", "vid":"xxx"},
{"aname":"account2", "pname":"pname3", "vname":"vname1", "vid":"xxx"},
]
I grouped the "vname" by "pname"
var groups = {};
$.each(values, function(key, values) {
if (!groups.hasOwnProperty(values.pname)) {
groups[values.pname] = {
aname : values.aname,
aid : values.aname,
pname : values.pname,
pid : values.pid,
vid: [],
vname: []
};
}
groups[values.pname].vname.push({
vname: values.vname,
vid: values.vid
});
});
Now I'm trying to loop:
$.each(groups, function(key, groups) {
$('#provider-accounts')
.append($("<optgroup></optgroup>")
.attr("label"," " + groups.aname))
.append($("<optgroup></optgroup>")
.attr("label"," " + groups.pname))
.append($("<option></option>")
.attr("value",groups.vid)
.text(" " + groups.vname[0].vname));
});
ISSUE
The output doesn't return all the options "vname" but only the first one.
How can I insert a loop in the loop. Something like this:
$.each(groups, function(key, groups) {
$('#provider-accounts')
.append($("<optgroup></optgroup>")
.attr("label"," " + groups.aname))
.append($("<optgroup></optgroup>")
.attr("label"," " + groups.pname))
for (var i = 0; i < groups.vname[0].vname.length; i++) {
.append($("<option></option>")
.attr("value",groups.vid)
.text(" " + groups.vname[0].vname[i]));
}
});
Any help?
Thanks
Instead of trying to chain it all into one chain I would create a separate object for the groups first. Then loop through the array and append the various options to the second group and finally append the groups to the select.
This seems to be easier to read also than the chained appends you are currently using
$.each(groups, function(key, groups) {
var $group1 = $("<optgroup>").attr("label", " " + groups.aname);
var $group2 = $("<optgroup>").attr("label", " " + groups.pname);
groups.vname.forEach(function(el) {
$group2.append(new Option(el.vname, el.vid));
});
$('#provider-accounts').append($group1, $group2);
});
#charlietfl's answer does it, and I agree that it would make your code more readable. But if you're still interested if such looping is possible - yes it is. You can use Array .map() for this and append the resulting array of Option elements.
.append(
groups.vname.map( vItem =>
$("<option></option>")
.attr("value",groups.vid)
.text(" " + vItem.vname)
));
I tried to fork your fiddle here: https://jsfiddle.net/b2yg5jvm/

Display pictures based on specific student ID

So after pulling all the information from my sql tables, I put them into 2 variables called response1 and response2.Shown below are what's currently inside the arrays. My goal is to display the pictures, beside each student. If a picture doesn't exsist, it can just be blank for now. So i've gotten the picture from DB to display by using base64 encode, but i'm only currently doing it for the id:20000001, since i'm not sure how to do it for other ones.
I had an idea to maybe replace
student_image= findItemByID(response2,'20000001');
with
student_image= findItemByID(response2,element.id); ?
but not sure if this is correct logic?
Inside my Object.keys final loop, how should I fix html+='<img src="data:image/jpeg;base64,'+student_image.photo+'">' so that it adds the image of the specific id?
Response1 array of object:
0: {Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001}
1: {Class_Student_Group: 2, names: "Lastname2, Firstname2", id: 20000002}
2: {Class_Student_Group: 3, names: "Lastname3, Firstname3", id: 20000003}
3: {Class_Student_Group: 5, names: "Lastname4, Firstname4", id: 20000004}
4: {Class_Student_Group: 3, names: "Lastname5, Firstname5", id: 20000005}
Response2 array of objects:
0: {student_id: "20000001", photo: ""}
1: {student_id: "20000001", photo: "/9j/4AAQSkZJRgABAQAAAQABAAD/4QB6RXhpZgAASUkqAAgAAA…9a1EtFKAnd09f/rVlwfdFbVw7LPIoOAGNYwjc/SIaxR//2Q=="}
2: {student_id: "20000002", photo: ""}
3: {student_id: "20000003", photo: ""}
final:
1: Array(4)
0: {Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001}
1: {Class_Student_Group: 1, names: "Lastname9, Firstname9", id: 20000009}
2: {Class_Student_Group: 1, names: "Lastname15, Firstname15", id: 20000015}
3: {Class_Student_Group: 1, names: "Lastname19, Firstname19", id: 20000019}
length: 4
__proto__: Array(0)
2: (4) [{…}, {…}, {…}, {…}]
3: (4) [{…}, {…}, {…}, {…}]
output so far:
<script type="text/javascript">
$(document).ready(function() {
var response= <?php echo json_encode($table); ?>;
var response2= <?php echo json_encode($result); ?>;
function findItemByID(arr, id) {
return arr.find((photoObj) => {
return photoObj.photo.trim().length !== 0 && photoObj.student_id === id
})
}
var final = {}
response.forEach(function(element) {
final[element.Class_Student_Group] = final[element.Class_Student_Group] || [];
final[element.Class_Student_Group].push(element);
});
let student_image =''
Object.keys(final).forEach(function(Group) {
let html = '';
//add the table opening tag to the html variable
html += '<table>';
//Append the 'category' header
html += '<tr>';
html += '<td><h1>'+"Group"+ Group+'</h1></td>';
html += '</tr>';
// Loop through the results for this 'category'
student_image= findItemByID(response2,'20000001');
final[Group].forEach(function(element) {
var randomImage = images[Math.floor(Math.random() * images.length)];
var names = element.names;
var id=element.id;
var img = "<img src=' " + randomImage+ " ' />";
html += '<tr>';
html += '<td><p>' + names + '</p></td> ';
html += '<td><p>' + id + '</p></td> ';
html+='<img src="data:image/jpeg;base64,'+student_image.photo+'">'
html += '</tr>';
});
//add the table closing tag to the html variable
html += '</table>';
$('#tables_container').append(html);
});
});
</script>
OK. Quite a few things going on here.
Basically the reason(s) the findItemByID() function wasn't working was because A. (and I have to assume you knew this) you were passing in the same ID every time it was called, B. by putting it before you called final[Group].forEach(function(element) you couldn't pass in the right value for the id, as the id is a property of that element variable, and C. === is a strict equality operator, which means it only returns true if the values are the same and they are the same type. In one array of objects that value is a string and in the other it's a number.
You are doing a lot of things out of order. Take a step back and try to think about what this code is intended to do and write it one step at a time, and break your steps into functions whenever practical like I have done here. Look over the changes I have made to your code, and the comments I added. Generally when writing code you want to use functions to make things more readable, and break them apart so you are dealing with the least amount of complexity as possible at any given time. A table works like table - > row - > column -- write your code that way.
I don't know anything about using Base64 for images in HTML, but a look at this link suggests that the data you have supplied here won't work. Check out the decoder in the accepted answer.
I changed the way you were iterating over your final object. This is probably mostly a matter of taste, but to me it's more readable. You can learn more about it here
Use better names! It's so much easier when you're trying to figure out why something is broken if you aren't also trying to remember what data is in response vs response2. Just call them studentDataArray and imageDataArray or something.
$(document).ready(function () {
loadTable();
});
let array1 = [
{ Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001 }
, { Class_Student_Group: 2, names: "Lastname2, Firstname2", id: 20000002 }
, { Class_Student_Group: 3, names: "Lastname3, Firstname3", id: 20000003 }
, { Class_Student_Group: 5, names: "Lastname4, Firstname4", id: 20000004 }
, { Class_Student_Group: 3, names: "Lastname5, Firstname5", id: 20000005 }
]
let array2 = [{ student_id: "20000001", photo: "" }
, { student_id: "20000001", photo: "/9j/4AAQSkZJRgABAQAAAQABAAD/4QB6RXhpZgAASUkqAAgAAA…9a1EtFKAnd09f/rVlwfdFbVw7LPIoOAGNYwjc/SIaxR//2Q==" }
, { student_id: "20000002", photo: "" }
, { student_id: "20000003", photo: "" }];
function findItemByID(arr, id) {
return arr.find((photoObj) => {
return photoObj.photo.trim().length !== 0 && photoObj.student_id == id // because the id property in the student object is a number and in the photo array it's a string, change this to '==', which evaluates '2' as equal to 2. === only returns true if they are the same type
//also you have been checking for a student_id property here, which doesn't exist on the second array's objects, so this wasn't returning anything
})
}
function getFinalObject(response) {
var final = {}
response.forEach(function (element) {
final[element.Class_Student_Group] = final[element.Class_Student_Group] || [];
final[element.Class_Student_Group].push(element);
});
return final;
}
function appendHtmlToDoc(final, response2, images) {
let html = '';
//add the table opening tag to the html variable
html += '<table>';
for (let Group in final) { //this will loop through final's properties, in this case, the 'groups'
if (final.hasOwnProperty(Group)) { //use hasOwnProperty to make sure you aren't looping through irrevelant properties (https://stackoverflow.com/questions/8312459/iterate-through-object-properties)
//Append the 'category' header
html += '<tr>';
html += '<td><h1>' + "Group" + Group + '</h1></td>';
html += '</tr>';
// Loop through the results for this 'category'
final[Group].forEach(function (element) { //you already have the Group array in the Group variable
let student_image = findItemByID(response2, element.id); //search for the image data using this element's id property
// var randomImage = images[Math.floor(Math.random() * images.length)]; //should pass 'images' into this function, but I don't know where it came from and randomImage/img isn't used in the code you provided, so I removed it
var names = element.names;
var id = element.id;
// var img = "<img src=' " + randomImage + " ' />";
html += '<tr>';
html += '<td><p>' + names + '</p></td> ';
html += '<td><p>' + id + '</p>';
if (student_image) { //check if something was returned when you searched for the photo, otherwise you'll have a blank image here
html += '<td><img src="data:image/jpeg;base64, ' + student_image.photo + '"></td>'; //I don't know anything about using images in HTML with base64, but a look at this link (https://stackoverflow.com/questions/8499633/how-to-display-base64-images-in-html) suggests that what you have provided won't work
}
//I also added a td around your img tag
html += '</tr>';
});
}
}
//add the table closing tag to the html variable
html += '</table>';
//console.log(html)
$('#tables_container').append(html);
}
function loadTable() {
//move your php script calls here
let finalObj = getFinalObject(array1);
appendHtmlToDoc(finalObj, array2);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="tables_container"></div>
Try:
if(!photo.id) {
// There's no image
} else {
// There's an image
}

Parse JSON with JavaScript to build a HTML string

I currently have built an API which posts JSON strings of objects. A simple example of the JSON is:
[ {
"id" : 0,
"name" : "test SAMPLE Att1 name",
"attributes" : [ {
"id" : -1,
"name" : "AttKey1",
"value" : "AttValue1"
}, {
"id" : -1,
"name" : "AttKey2",
"value" : "AttValue2"
} ]
} ]
My issue lies in my client code here:
function loadSamples() {
$("#content").children().remove();
$.getJSON("/api/samples", function (data) {
$.each(data, function (key, val) {
$("<tr><td>" + val.id + "</td><td>" + val.name + "</td><td>" + val.attributes + "</td>" +
"</tr>").appendTo("#content");
});
initCallbacks();
});
}
I am iterating through each sample I send (in this case only one, and appending the field values to the HTML string. How can I iterate through attributes and append each attribute.key and attribute.value to the string?
A picture of the current problem:
You can try to use this code instead of val.attributes
$.map(val.attributes, function(item){
return item.key + ':' +item.value;
}).join(',')
Use another loop, iterate through all attributes, build an array of attributes in format "property: value" and then append joined array to HTML:
$.each(data, function (key, val) {
var attributes = [];
for (var prop in val.attributes) {
var value = val.attributes[prop];
attributes.push(prop + ": " + value);
}
$("<tr><td>" + val.id + "</td><td>" + val.name +
"</td><td>" + attributes.join(",") + "</td>" + "</tr>").appendTo("#content");
});
If you feel nerdy you can just serialize the object back into a JSON string like this:
... + JSON.stringify(val.attributes) + ...
It is recursive, has a standard syntax (JSON) and doesn't require any support function or additional code at all.

jQuery each() breaking on null

I have a JSON object that I am looping over with each() to add table rows to a table. I can't ensure the completeness of the data presented in the JSON arrays and I occasionally run into some NULLs.
For instance:
// A GOOD ARRAY
{
id: "193",
location: {
city: "Atlanta",
state: "GA"
},
name: "John"
},
// NOW WE STUMBLE UPON A BAD ARRAY WITH A NULL
{
id: "194",
location: {
city: "Boise",
state: null
},
name: "Frank"
},
{...}
Now, when I am dealing with JSON objects that have no NULL values, the each() loops over with no problems. As soon as I encounter a member with NULL anywhere in the array, the looping breaks.
This is how I am looping over this:
$.getJSON("/getstuff/jsonprovider.php", function (data) {
var results = data.parentnode;
var tableThing = $(".myTable tbody");
var i = 0;
$.each(results, function () {
tableThing.append('<tr><td></td><td>' + results[i].id + '</td><td>' + results[i].name + '</td><td>' + results[i].location.city + ', ' + results[i].location.state + '</td></tr>');
i++;
});
});
Should I be investigating something other than each() here, or should I be using a completely different method?
Thank you
Since your data may have nulls, you need to make sure that the data exists before you attempt to use it. It is also more efficient to only use .append once. Below i'm using a default empty object and $.extend deep copy to ensure that the object we are pulling data from always has all data values defined, even if the value isn't in the json. I'm still not sure how null's will be handled at this point.
var emptyObj = {
id: "",
name: "",
location: {
city: "",
state: ""
}
},htmlToAppend = "";
$.each(results, function (i,obj) {
var newObj = $.extend(true,{},emptyObj,obj);
htmlToAppend += '<tr><td></td><td>' + newObj.id + '</td><td>' + newObj.name + '</td><td>' + newObj.location.city + ', ' + newObj.location.state + '</td></tr>';
});
tableThing.append(htmlToAppend);
The proper way to do a $.each is like this:
var myObj = {...};
$.each(myObj, function(k, v){
//..
});
You need two parameters above:
k holds the index or the key
v holds the value at that index or key
If you were going to use a counter variable like i you might as well use JavaScripts for in loop:
for(var i in myObj){
//..
}

Using dynamic search parameters with Sequelize.js

I'm trying to follow the Sequelize tutorial on their website.
I have reached the following line of code.
Project.findAll({where: ["id > ?", 25]}).success(function(projects) {
// projects will be an array of Projects having a greater id than 25
})
If I tweak it slightly as follows
Project.findAll({where: ["title like '%awe%'"]}).success(function(projects) {
for (var i=0; i<projects.length; i++) {
console.log(projects[i].title + " " + projects[i].description);
}
});
everything works fine. However when I try to make the search parameter dynamic as follows
Project.findAll({where: ["title like '%?%'", 'awe']}).success(function(projects) {
for (var i=0; i<projects.length; i++) {
console.log(projects[i].title + " " + projects[i].description);
}
});
It no longer returns any results. How can I fix this?
Now on Sequelize you can try this
{ where: { columnName: { $like: '%awe%' } } }
See http://docs.sequelizejs.com/en/latest/docs/querying/#operators for updated syntax
I think you would do that like this:
where: ["title like ?", '%' + 'awe' + '%']
So if you were doing this with an actual variable you'd use:
Project.findAll({where: ["title like ?", '%' + x + '%']}).success(function(projects) {
for (var i=0; i<projects.length; i++) {
console.log(projects[i].title + " " + projects[i].description);
}
});
Please try this code
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
{ where: { columnName: { [Op.like]: '%awe%' } } }
I would do it in this way:
Project.findAll({where: {title: {like: '%' + x + '%'}, id: {gt: 10}}).success(function(projects) {
for (var i=0; i<projects.length; i++) {
console.log(projects[i].title + " " + projects[i].description);
}
});
In this way you can have nicely more WHERE clausas
It might be cleaner to leverage the Sequelize.Utils.format function
The accepted answer of ["columnName like ?", '%' + x + '%'] for the where clause results in this error in Sequelize 4.41.1: "Support for literal replacements in the where object has been removed."
Assuming: modelName.findAll({ where : { columnName : { searchCriteria } } });
Using [Op.like]: '%awe%' or $like: '%awe%' } as the searchCriteria (where 'awe' is the value you want to find in columnName) both result in SQL with a LIKE clause of LIKE '\"%awe%\"'. Notice the extra quotation marks. [Op.like] and $like are aliases of each other and neither answer the OP's question because they don't allow dynamic search parameters.
Using [Op.like] : `%${parameter}%` as the searchCriteria (where 'parameter' is the parameter whose value you want to find in columnName) resulted in SQL with a LIKE clause of LIKE '\"%findMe\"' when parameter= 'findMe'. Again, notice the extra quotation marks. No results.
An answer in another StackOverflow post suggested using [Op.like]: [`%${parameter}%`] for the searchCriteria (where 'parameter' is the parameter whose value you want to find in columnName). Notice the square brackets! This resulted in SQL with a LIKE clause of LIKE '[\"%findMe%\"]' when parameter= 'findMe'. Again notice the extra quotation marks and the square brackets. No results.
For me, the solution was to use a raw query:
Sequelize.query('SELECT * FROM tableName WHERE columnName LIKE "%searchCriteria%"');

Categories

Resources