Merge different rows of an array using lodash - lodash

I have a JSON array which has the following entries:
[{"customer":"xyz","date":"10.10.2014","attr1":"ABC","attr2":"001"},{"customer":"xyz","date":"10.10.2014","attr3":"XYZ","attr4":"123"},{"customer":"xyz","date":"11.10.2014","attr1":"DEF","attr2":"002"},{"customer":"xyz","date":"11.10.2014","attr3":"DDD","attr4":"222"}]
Is there a way, using lodash, I can merge the array so that this becomes:
[{"customer":"xyz","date":"10.10.2014","attr1":"ABC","attr2":"001","attr3":"XYZ","attr4":"123"},{"customer":"xyz","date":"11.10.2014","attr1":"DEF","attr2":"002","attr3":"DDD","attr4":"222"}]
Basically use the "date" attribute to merge multiple rows with different JSON attributes into a single JSON object entry ?

Use _.groupBy() to group the objects by date. Then _.merge() each group:
var customers = [{"customer":"xyz","date":"10.10.2014","attr1":"ABC","attr2":"001"},{"customer":"xyz","date":"10.10.2014","attr3":"XYZ","attr4":"123"},{"customer":"xyz","date":"11.10.2014","attr1":"DEF","attr2":"002"},{"customer":"xyz","date":"11.10.2014","attr3":"DDD","attr4":"222"}];
var result = _(customers)
.groupBy('date') // group the objects by date
.map(function(item) { // map each group
return _.merge.apply(_, item); // merge all objects in the group
})
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.js"></script>

Here is a solution using lodash 3.10.1. I assumed you want to merge each pair and that the second element of a pair will override existing properties from the first one (if there are such).
var source = [{"customer":"xyz","date":"10.10.2014","attr1":"ABC","attr2":"001"},{"customer":"xyz","date":"10.10.2014","attr3":"XYZ","attr4":"123"},{"customer":"xyz","date":"11.10.2014","attr1":"DEF","attr2":"002"},{"customer":"xyz","date":"11.10.2014","attr3":"DDD","attr4":"222"}];
var chunked = _.chunk(source, 2);
var result = _.map(chunked, _.spread(_.merge));
console.log(result);
And here is a working jsbin.

Related

how to use lodash filter function using variable

I am using lodash in one of my projects to achieve filter. My requirement is we have different SELECT options that are generated dynamically. And these are populated with json.
So my filter function that I need should be generic. For example if there are 3 drop downs.
dropdown1. populated with values whose json_property is ABC_CODE="002"
dropdown2. populated with values whose json_property is xyz_CODE="002"
dropdown2 values should change based on dropdown1 selection
I have a masterdata list, which tells this information.
The loadash _.filter function should use varaibles. Because this filter should be used dynamically for different select options.
ex:
var a=_.filter($scope.masterData, function(e){
return _.indexOf(v, e.ABC_CODE) != -1;
});
console.log(a); //returns array of objects
I get the values.
How can I replace ABC_CODE from a javascript variable. like e.tempVar where tempVar is ABC_CODE
use bracket notation
var a = _.filter($scope.masterData, function(e) {
var key = ABC_CODE;
return _.indexOf(v, e[key]) != -1;
});
console.log(a); //returns array of objects

"update" query - error invalid input synatx for integer: "{39}" - postgresql

I'm using node js 0.10.12 to perform querys to postgreSQL 9.1.
I get the error error invalid input synatx for integer: "{39}" (39 is an example number) when I try to perform an update query
I cannot see what is going wrong. Any advise?
Here is my code (snippets) in the front-end
//this is global
var gid=0;
//set websockets to search - works fine
var sd = new WebSocket("ws://localhost:0000");
sd.onmessage = function (evt)
{
//get data, parse it, because there is more than one vars, pass id to gid
var received_msg = evt.data;
var packet = JSON.parse(received_msg);
var tid = packet['tid'];
gid=tid;
}
//when user clicks button, set websockets to send id and other data, to perform update query
var sa = new WebSocket("ws://localhost:0000");
sa.onopen = function(){
sa.send(JSON.stringify({
command:'typesave',
indi:gid,
name:document.getElementById("typename").value,
}));
sa.onmessage = function (evt) {
alert("Saved");
sa.close;
gid=0;//make gid 0 again, for re-use
}
And the back -end (query)
var query=client.query("UPDATE type SET t_name=$1,t_color=$2 WHERE t_id = $3 ",[name, color, indi])
query.on("row", function (row, result) {
result.addRow(row);
});
query.on("end", function (result) {
connection.send("o");
client.end();
});
Why this not work and the number does not get recognized?
Thanks in advance
As one would expect from the initial problem, your database driver is sending in an integer array of one member into a field for an integer. PostgreSQL rightly rejects the data and return an error. '{39}' in PostgreSQL terms is exactly equivalent to ARRAY[39] using an array constructor and [39] in JSON.
Now, obviously you can just change your query call to pull the first item out of the JSON array. and send that instead of the whole array, but I would be worried about what happens if things change and you get multiple values. You may want to look at separating that logic out for this data structure.

How do I iterate through a list of items in a Ext.dataview.List

I'm currently trying to find out how to set items to be selected on a list in ST2.
I've found the following:
l.select(0, true);
l.select(1, true);
which would select the first 2 items on my list. But the data coming from the server is in csv format string with the ids of the items in the list to be selected.
e.g. "4, 10, 15"
So I currently have this code at the moment.
doSetSelectedValues = function(values, scope) {
var l = scope.getComponent("mylist");
var toSet = values.split(",");
// loop through items in list
// if item in list has 'id' property matching whatever is in the toSet array then select it.
}
The problem is I can't seem to find a way of iterating over the items in the list and then inspect the "id" property of the item to see if it matches with the item in the array.
l.getItems()
Doesn't seem to return an array of items. The list is populated via a store with the "id" & "itemdesc" properties. I just want to be able to select those items from a csv string. I've scoured the Api on this and I can't seem to find a way of iterating over the items in the list and being able to inspect its backing data.
the Ext.List's items are not the items you are looking for. The items under the Ext.List object are those:
Ext.create('Ext.List', {
fullscreen: true,
itemTpl: '{title}',
store: theStore,
**items: [item1, item2]**
});
Granted, usually an Ext.List doesn't have items like these. What you are looking for are the Ext.Store items. The Ext.Store items are the exact same items in the same order as presented in the Ext.List.
To iterate over those, and select the corresponding items in the list, do the following:
var s = l.getStore();
var itemIndicesToSelect = [];
for (var i = 0 ; i < s.data.items.length ; i++){
if (arrayContainsValue(toSet, s.data.items[i].data.id)){
itemIndicesToSelect.push(i);
}
}
for (var i = 0 ; i < itemIndicesToSelect.length ; i++){
l.selectRange(itemIndicesToSelect[i], itemIndicesToSelect[i], true);
}
You would have to implement the function arrayContainsValue (one possible solution).
doSetSelectedValues = function(values, scope) {
var l = scope.getComponent("mylist"),
store = l.getStore(),
toSet = values.split(",");
Ext.each(toSet, function(id){
l.select(store.getById(id), true);
});
}

Conditionally adjust visible columns in Rally Cardboard UI

So I want to allow the user to conditionally turn columns on/off in a Cardboard app I built. I have two problems.
I tried using the 'columns' attribute in the config but I can't seem to find a default value for it that would allow ALL columns to display(All check boxes checked) based on the attribute, ie. the default behavior if I don't include 'columns' in the config object at all (tried null, [] but that displays NO columns).
So that gets to my second problem, if there is no default value is there a simple way to only change that value in the config object or do I have to encapsulate the entire variable in 'if-else' statements?
Finally if I have to manually build the string I need to parse the values of an existing custom attribute (a drop list) we have on the portfolio object. I can't seem to get the rally.forEach loop syntax right. Does someone have a simple example?
Thanks
Dax - Autodesk
I found a example in the online SDK from Rally that I could modify to answer the second part (This assumes a custom attribute on Portfolio item called "ADSK Kanban State" and will output values to console) :
var showAttributeValues = function(results) {
for (var property in results) {
for (var i=0 ; i < results[property].length ; i++) {
console.log("Attribute Value : " + results[property][i]);
}
}
};
var queryConfig = [];
queryConfig[0] = {
type: 'Portfolio Item',
key : 'eKanbanState',
attribute: 'ADSK Kanban State'
};
rallyDataSource.findAll(queryConfig, showAttributeValues);
rally.forEach loops over each key in the first argument and will execute the function passed as the second argument each time.
It will work with either objects or arrays.
For an array:
var array = [1];
rally.forEach(array, function(value, i) {
//value = 1
//i = 0
});
For an object:
var obj = {
foo: 'bar'
};
rally.forEach(obj, function(value, key) {
//value = 'bar'
//key = 'foo'
});
I think that the code to dynamically build a config using the "results" collection created by your query above and passed to your sample showAttributeValues callback, is going to look a lot like the example of dynamically building a set of Table columns as shown in:
Rally App SDK: Is there a way to have variable columns for table?
I'm envisioning something like the following:
// Dynamically build column config array for cardboard config
var columnsArray = new Array();
for (var property in results) {
for (var i=0 ; i < results[property].length ; i++) {
columnsArray.push("'" + results[property][i] + "'");
}
}
var cardboardConfig = {
{
attribute: 'eKanbanState',
columns: columnsArray,
// .. rest of config here
}
// .. (re)-construct cardboard...
Sounds like you're building a neat board. You'll have to provide the board with the list of columns to show each time (destroying the old board and creating a new one).
Example config:
{
attribute: 'ScheduleState'
columns: [
'In-Progress',
'Completed'
]
}

Adding a index to collection using EF 4.1 and XAML (For a highscore table)

I have a webservice I call from a WP7 app. I get a list of high scores in a table (name/score).. What is the simpliest way to add a 3rd column on the far left which is simply the row?
Do I need to add a property to the entity? Is there someway to get the row #?
I tried these things below with no success..
[OperationContract]
public List<DMHighScore> GetScores()
{
using (var db = new DMModelContainer())
{
// return db.DMHighScores.ToList();
var collOrderedHighScoreItem = (from o in db.DMHighScores
orderby o.UserScore ascending
select new
{
o.UserName,
o.UserScore
}).Take(20);
var collOrderedHighScoreItem2 = collOrderedHighScoreItem.AsEnumerable().Select((x, i) => new DMHighScoreDTO
{
UserName = x.UserName,
UserScore = x.UserScore
}).ToList();
}
}
[DataContract]
public class DMHighScoreDTO
{
int Rank;
string UserName;
string UserScore;
}
So lets assume you want to load top 100 users in leaderboard and you want to have their rank included:
[OperationContract]
public List<ScoreDto> GetTop100()
{
// Linq to entities query
var query = (from u from context.Users
order by u.Score
select new
{
u.Name,
u.Score
}).Take(100);
// Linq to objects query from working on 100 records loaded from DB
// Select with index doesn't work in linq to entities
var data = query.AsEnumerable().Select((x, i) => new ScoreDto
{
Rank = i + 1,
Name = x.Name,
Score = x.Score
}).ToList();
return data;
}
what will the row number be used for? if this is for ordering might I suggest adding a column named Order, then map the column to your entity.
if you require a row index, you could also call the .ToList() on the query and fetch the index locations for each entity.
Edit:
you could add the Rank property and set it to Ignore. This will enable you to go through the collection set the rank with a simple for loop. This will also not be persisted in the database. It will also not have any required columns in the database.
It does add an extra iteration.
the other way to go about it. This would be to add the rank number in the generated UI and not in the data collection being used to bind.