akrymski/espresso.js

Collection.Find method (probable) bug

Closed this issue · 7 comments

Hi Artemi.
I was trying to find a model in a collection, passing some of its attributes, but without the id.
Contrary to my expectations, the collection's find method yielded "undefined", although I was certain that there was the model whose attributes I was looking for.
I think I may have found a possible issue.

Changing (from line 80 onwards)

isEqual: function(attr) {
    for (var key in attr) {
      if (!isEqual(attr[key], this[key])) return false;
    }
    return true;
  },

To

isEqual: function(attr) {
    for (var key in attr) {
      if (isEqual(attr[key], this[key])) return true;
    }
    return false;
  },

made it possible to find a model in a collection, by passing some of its attributes (without the id).

Sorry, Artemi. Made a mistake. Cannot make find method to look for models in a collection without passing the id

This may be the problem:

  // find index of matching object, eg: findIndex({ id: 1 });
  findIndex: function(attr) {
    var items = this.items, isEqual = Model.prototype.isEqual, id;
    if (this.idAttribute in attr) id = this.idAttribute;
    for (var i = 0, len = items.length; i < len; i++) {
      if (id) {
        if (attr[id] === items[i][id]) return i;
      } else if (isEqual.call(attr, items[i])) return i;      
    }
    return -1;
  },

I changed the elseif part from:

else if (isEqual.call(attr, items[i])) return i; 

to:

else if (isEqual.call(items[i], attr)) return i; 

And collection find method works (I think) as expected

good post, i ended up making my own .matching(matchingobj) method because i had the same problem

op i think you want .filter. find only works with the "id" attribute.

so

mycoll.find({id: 123})

or

mycoll.filter(function (item, i) {  if (item.myprop == 'whatever') return true; return false; })

or you can make your own matches function like this

Espresso.Collection.prototype.matching = function(matchObj){
    var keys = Object.keys(matchObj)
    return this.filter(function(x){
      for (var i = 0; i < keys.length; i++) {
        if(typeof(x[keys[i]]) === 'undefined' || x[keys[i]] !== matchObj[keys[i]])
          return false
      }
      return true
    })
  }

c = new Espresso.Collection( [{id:0, misc:true}] )
console.log(c.matching({misc:true}) // [ { id: 0, misc: true } ]

anyway passing this on to artemi, im not a JS expert

tbh i have no idea about .call and .apply but heres what i found:

obj1 = { id:0, b: 2 }
console.log( isEqual(obj1, obj1) )  // true
console.log( isEqual.call(obj1, obj1) ) // false

isEqual.call and isEqual return different things on chrome, .call always returns false

https://jsfiddle.net/f902s94n/

bumping for OP, i think you want .filter() -- i edited my post above with an explanation.

Thanks for spotting the bug, just pushed a fix