How to pluck multiple attributes from a Backbone collection? - javascript

I am trying to pluck multiple attributes from a Backbone collection but it returns undefined.
collection
{
id:1,
name:"raju",
age:23,
sex:male,
hobbies:..
}
{
id:2,
name:"ramesh",
age:43,
sex:male,
hobbies:..
}
... //many models
I am trying to get multiple attributes from collection.
collection.pluck(["id","name","age","sex"]);
Expected output
[{//multiple attributes},{}]
is there any alternative way to get multiple attributes?

As #elclanrs said, collection.pluck extracts a single attribute, you will have to use _.map with a custom extraction function. Something like
var c = new Backbone.Collection([
{id: 1, name: "raju", age: 23, sex: "male"},
{id: 2, name: "ramesh", age: 43, sex: "male"}
]);
var plucked = c.map(function (model) {
return _.pick(model.toJSON(), ["name", "age"]);
});
console.log(plucked);
And a demo http://jsfiddle.net/U7p9u/
You could simplify this call by combining Collection.invoke and Model.pick
var c = new Backbone.Collection([
{id: 1, name: "raju", age: 23, sex: "male"},
{id: 2, name: "ramesh", age: 43, sex: "male"}
]);
plucked = c.invoke("pick", ["name", "age"]);
console.log(plucked);
http://jsfiddle.net/U7p9u/5/
In a similar spirit, if your extraction function is defined on the prototype of your models:
var M = Backbone.Model.extend({
mypluck: function () {
return this.pick("name", "age");
}
});
var C = Backbone.Collection.extend({
model: M
});
var c = new C([
{id: 1, name: "raju", age: 23, sex: "male"},
{id: 2, name: "ramesh", age: 43, sex: "male"}
]);
var plucked = c.invoke("mypluck");
console.log(plucked);
http://jsfiddle.net/U7p9u/3/

In the docs it says:
"[pluck is the] Equivalent to calling map and returning a single
attribute from the iterator."
This leads me to believe that it isn't possible with multiple properties because you're basically replacing one item in the collection with one of its properties. So basically you're doing this:
var collect = [{a:'foo',b:'baz'},{a:'lol',b:'fur'}];
var key = 'a';
var result = collect.map(function(o){ return o[key] });
A possible solution would be to return an array and then flatten it, something like this:
result = [].concat.apply([],collect.map(function(o){ return [o.a,o.b]; }));
console.log(result); //=> ["foo", "baz", "lol", "fur"]

http://jsfiddle.net/CoryDanielson/Lj3r85ew/
You could add select methods to collections and models.
(or name it whatever you feel is appropriate)
/**
Backbone Model Select/Multi-get -------------------------------------------
*/
Backbone.Model.prototype.select = function(props) {
if ( arguments.length > 1 ) {
props = slice.call(arguments);
}
if ( _.isArray(arguments[0]) ) {
props = arguments[0];
}
// If requesting multiple, return all props
if ( _.isArray(props) ) {
return _.object(props, _.map(props, _.bind(this.get, this)));
}
// Else, return single property
return this.get(props);
}
/**
Backbone Collection Select ------------------------------------------------
*/
Backbone.Collection.prototype.select = function(props) {
if ( arguments.length > 1 ) {
props = slice.call(arguments);
}
if ( _.isArray(arguments[0]) ) {
props = arguments[0];
}
return _.map(this.models, function(m) {
return m.select(props);
});
}
This would allow you to select multiple properties across all models of a collection, or select multiple properties on a model.
collection.select('id', 'first', 'last'); // or ['id', 'first', 'last']
model.select('first', 'last'); // or ['first', 'last']

Related

How to filter few properties of an object which is in Array of objects if one property equals property from another object

I have a object which has some properties for one user, and I have array of objects which is returned from API.
My goal is to check which object of Array of objects has the same property as the one single initial object, and then it should return only part of it's properities.
I have tried to use .map on Array of objects but it seems not workig.
Below is the code example. I have also prepared codesandbox if You wish.
const user =
{
name: "jan",
lastName: "kowalski",
fullName: "jan kowalski",
car: "audi"
}
;
const usersAnimal = [
{
name: "jan",
lastName: "kowalski",
fullName: "jan kowalski",
animal: "cat",
animalSize: "small",
animalName: "Bat"
},
{
name: "john",
lastName: "smith",
fullName: "john smith",
animal: "dog",
animalSize: "middle",
animalName: "Jerry"
},
{
name: "Anna",
lastName: "Nilsson",
fullName: "Anna Nilsson",
animal: "cow",
animalSize: "big",
animalName: "Dorrie"
}
];
const filtered = usersAnimal.map((userAnimal)=>userAnimal.fullName === user.fullName && return userAnimal.animalName & userAnimal.animalSize & userAnimal.animal);
thanks
https://codesandbox.io/s/admiring-edison-qxff42?file=/src/App.js
For case like this, it would be far easier if you filter it out first then proceed using map:
const filtered = usersAnimal
.filter((animal) => animal.fullName === user.fullName)
.map(({ animalName, animalSize, animal }) => {
return {
animalName,
animalSize,
animal
};
});
I am providing a for loop solution as I haven't learnt many array methods in javascript.
For me the simplest option is to use a for loop and an if check to loop through the arrays values to check for included values.
for (let v in usersAnimal) {
if (usersAnimal[v].fullName === user.fullName) {
console.log(usersAnimal[v])
}
}
The code above will log the entire usersAnimal object containing the fullname we are looking for.
{
name: 'jan',
lastName: 'kowalski',
fullName: 'jan kowalski',
animal: 'cat',
animalSize: 'small',
animalName: 'Bat'
}
commented for further understanding
for (let v in usersAnimal) {
//loops though the array
if (usersAnimal[v].fullName === user.fullName) {
//when the index value 'v' has a fullname that matches the user fullname value
// it passes the if check and logs that object value
return console.log(usersAnimal[v])
//return true...
}
//return null
}
//etc
If you want to filter, I recommend you to use filter.
The map method will create a new array, the content of which is the set of results returned by each element of the original array after the callback function is operated
const user = {name:"jan",lastName:"kowalski",fullName:"jan kowalski",car:"audi"};
const usersAnimal = [{name:"jan",lastName:"kowalski",fullName:"jan kowalski",animal:"cat",animalSize:"small",animalName:"Bat"},{name:"john",lastName:"smith",fullName:"john smith",animal:"dog",animalSize:"middle",animalName:"Jerry"}];
// Get an array of matching objects
let filtered =
usersAnimal.filter(o => o.fullName === user.fullName);
// You get the filtered array, then you can get the required properties
filtered.forEach(o => {
console.log(
'animal:%s, animalSize:%s, animalName:%s',
o?.animal, o?.animalSize, o?.animalName
);
});
// Then use map to process each element
filtered = filtered.map(o => {
const {animal, animalSize, animalName} = o;
return {animal, animalSize, animalName};
});
console.log('filtered', filtered);

How does Ember map function expect parameters?

I want to understand how the below code works in EmberJS?
Ember.$.map($this.get('myMap'), function(entitlements, id) {
// What is entitlements & id here & what should be $this.get('myMap')?
})
is this conventional/standard JS syntax ?
Any examples would be great ?
Ember.$ with lead you to jQuery, so you're using jQuery's map method.
Essentially what it does it call a function for each element in the array, allowing you to "map" that value to another and return it to be added to a new array. For instance:
If you have an array of javascript objects like var names = [{ name: 'John', age: 12}, {name: 'Fred', age: 14}] and you wanted to extract all names to a new array you could do:
var names = [{ name: 'John', age: 12}, {name: 'Fred', age: 14}];
var result = Ember.$.map(names, function(instance, index) {
return instance.name
})
console.log(result) //Would print ['John', 'Fred'];
You could do all sort of things like return new objects to be added to the array.

(javascript) Is it possible to split an array of different object types into multiple arrays of one object type

So I have an array that contains objects with different attributes and I want to know how I can make multiple arrays with objects with the same attributes of the whole array.
I want to go from this
[
{name:”test”, place:”country”},
{name:”walkAndEat”, Long=100,Lat:15,Location:”place name”},
{name:”test2”,place:”Europe”}
]
To
[
{name:”test”, place:”country”},
{name:”test2”,place:”Europe”}
]
[
{name:”walkAndEat”, Long:100,Lat:15,Location:”place name”}
]
If you see objects being equal as having the same properties, you can keep the keys as (stringified) indices in a collection object and check if a properties-key already exists:
var arrcoll = {};
function add(o){
var keys = JSON.stringify(Object.keys(o).sort());
var arr = arrcoll[keys];
if(arr)
arr.push(o);
else
arrcoll[keys] = [o];
return arr;
}
This can be done on the fly or on a pre existing array as shown in this Fiddle
Suppose you have a list of objects that have different properties like so:
var placesOrPeople = [
{ name: 'Seymour Skinner', occupation: 'Principal' },
{ name: 'Kwik-E-Mart', lat: 23, long: 100 },
{ name: 'Sideshow Bob', occupation: 'Comic Foil' },
{ name: 'Flaming Tyre Yard', lat: 12, long: 88 },
{ name: 'Joe Quimby', occupation: 'Mayor' }
];
And you want them sorted into separate lists like so:
places = [
{ name: 'Kwik-E-Mart', lat: 23, long: 100 },
{ name: 'Flaming Tyre Yard', lat: 12, long: 88 }
];
people = [
{ name: 'Seymour Skinner', occupation: 'Principal' },
{ name: 'Sideshow Bob', occupation: 'Comic Foil' },
{ name: 'Joe Quimby', occupation: 'Mayor' }
];
You can use the built-in Array.filter command like so:
var places = placesOrPeople.filter(function(currentPlaceOrPerson) {
if (currentPlaceOrPerson.occupation !== undefined) {
// it must be a person, since locations don't have occupations
return true;
} else {
return false;
}
});
var people = placesOrPeople.filter(function(currentPlaceOrPerson) {
if (currentPlaceOrPerson.lat !== undefined && currentPlaceOrPerson.long !== undefined) {
// it must be a place, since people don't have co-ordinates
return true;
} else {
return false;
}
});
Javascript Objects are not set types, they are dynamic, meaning you can change them during execution.
JavaScript is a loosely typed or a dynamic language. That means you don't have to declare the type of a variable ahead of time. The type will get determined automatically while the program is being processed. That also means that you can have the same variable as different types:
var anything = arrayOfAnyOtherType[0];
is valid... If you loop your source array and populate it, you can define any behavior to each object

I have two arrays, how do I find matchings elements and perform some action? (lodash)

var array1 = [{Age: 24, Name: "Test", StudentID: 101, Checked: false}, {Age:25, Name: "Test", StudentID: 102, Checked: false}];
var array2 = [{ID: 101}];
If any element in array1 has a property of StudentID that is equal to an ID property present in array2 I'd like to set the Checked property in array1 to true.
Any tips? I'd like to do this without writing nested _.each statements.
This is my first take; however, I believe _.some performs an interation anyway.
_.each($scope.array1, function(element1) {
if(_.some($scope.array2, { ID: element1.ID })) {
element1.Checked = true;
}
});
You''ll have to use two loops, since you have two arrays of random length. But you don't have to nest them. Create a map from the array of IDs and then check the index.
var availableIDs = array2.map(function ( item ) { return item.ID; });
array1.forEach(function ( item ) {
if (availableIDs.indexOf(item.StudentID) !== -1) item.Checked = true;
});
Using lodash, use a sequence in which you create a map of items in array1, using _.indexBy(). Create an array of ids from array2 using _.pluck(), and use them with _.at() to get the selected items. Iterate the returned objects using _.forEach() to set the Checked property to true, and .commit() to apply the changes:
function checkById(items, selected) {
_(items) // start chained sequence
.indexBy('StudentID') // create a map of student objects by ids
.at(_.pluck(selected, 'ID')) // create an array of IDs from the objects in the selected array
.forEach(function(item) { // change the items Checked to true
item.Checked = true;
})
.commit(); // executes the chained sequence
}
var array1 = [{
Age: 24,
Name: "Test1",
StudentID: 101,
Checked: false
}, {
Age: 25,
Name: "Test2",
StudentID: 102,
Checked: false
}, {
Age: 22,
Name: "Test3",
StudentID: 103,
Checked: false
}, {
Age: 28,
Name: "Test4",
StudentID: 104,
Checked: false
}];
var array2 = [{
ID: 101
}, {
ID: 104
}];
checkById(array1, array2);
console.table(array1);
document.getElementById('demo').innerText = JSON.stringify(array1, null, ' ');
<script src="https://cdn.jsdelivr.net/lodash/3.10.1/lodash.min.js"></script>
<pre id="demo"></pre>
using a simple mapping function you can compose an easy search through all objects
var array1 = [{Age: 24, Name: "Test", StudentID: 101, Checked: false}, {Age:25, Name: "Test", StudentID: 102, Checked: false}];
var array2 = [{ID: 101}];
function search(studentList,searchQuery) {
var results = [];
studentList.forEach(function(student,sIndex) {
searchQuery.forEach(function(search,qIndex) {
if(search.ID == student.StudentID) {
results.push(student);
}
});
})
return results;
}
search(array1,array2);
what the forEach function does is iterate over each element, passing along the object of the index it's iterating, and the index that object is at.
By having a double nested map it's easy to iterate over the objects and then compare them according to the rules you define.
Then by using a scoped variable you can push matching values into that array, giving you a nice, neat clean result to return.
Now please mind, this is not the most efficient way to handle this. You could do a test which arary is longest and have that one iterate the least time.
So if there are more students than search parameters iterate the students once. If there are more search parameters than students, iterate the search paramateters once.
also you could chooose to 'prefilter" the arrays by sorting them on the index you wish to sort on, skip the ones you don't need by simple min/max exclusion and such.
But you'd be better off using a database query for searching with large quantities of data.
But if you only have a dataset of about a 1000 or so this will suffice.
Try this snippet:
_.each(array1, function (el) {
el.Checked = !!(JSON.stringify(array2).indexOf(el.StudentID) + 1) || el.Checked;
});
Or, you can do without lo-dash.js(with pure JavaScript)
var array1 = [{Age: 24, Name: "Test", StudentID: 101, Checked: false}, {Age:25, Name: "Test", StudentID: 102, Checked: false}];
var array2 = [{ID: 101}];
var students = array1.filter(function(data){
var isTrue = !!(JSON.stringify(array2).indexOf(data.StudentID)+1);
data.Checked = isTrue || data.Checked;
return isTrue;
})
console.log(students)

How to get the indices of the objects in this array / JS

If I have an array of objects:
myArray[person{}, person{}, person{}]
And each person can contain an array of Children objects like this:
person{
name: 'XXX',
age: 'XXX',
children: [{
name: 'XXX',
age: 'XXX'
},{
name: 'XXX',
age: 'XXX'
},{
name: 'XXX',
age: 'XXX'
}]
}
How can I get the index of each Person in myArray and also the index of the objects in the Children array?
I'm getting the index of the Person objects in myArray like this, using indexOf(), which is working:
function getObjectIndex(myObject) {
var myArray = _.flatten(_.values(objects));
var ret = myArray.indexOf(myObject);
return ret; //RETURNS 0, 1, 2 etc...
}
I'm unsure how to expand the functionality of getObjectIndex to get the indices of the Children objects in each Person
function getObjectIndex(myObject) {
var myArray = _.flatten(_.values(objects));
var ret = myArray.indexOf(myObject);
if (myObject.children.length > 0){
//UNSURE WHAT LOGIC TO APPLY HERE
ret += ;
}
return ret;
}
If there are any children objects present, I ideally would like getObjectIndex to return:
Person index in myArray _ Children index in Person
So if there are three Children object in a Person:
0_0
0_1
0_2
Any help or suggestions would be very much appreciated.
If you pass an array to map then the second parameter to the iterator function is the index of the object. This can be used to get the result you want:
var indexArrays = _.map(myArray, function(person, personIndex){
return _.map(person.children, function(child, childIndex){
return personIndex + '_' + childIndex;
});
});
var indices = _.flatten(indexArrays);

Categories