kongaraju
kongaraju

Reputation: 9586

How to pluck multiple attributes from a Backbone collection?

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?

Upvotes: 9

Views: 8780

Answers (3)

nikoshr
nikoshr

Reputation: 33334

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/

Upvotes: 17

Cory Danielson
Cory Danielson

Reputation: 14501

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']

Upvotes: 0

elclanrs
elclanrs

Reputation: 94101

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"]

Upvotes: 3

Related Questions