loops - JavascriptNodeJS: Best way to find an specific object by id inside an arraycollection of objects - Stack Overflow

OverviewSo I have pulled out a document from my database. Inside is a nested collection of objects. Eac

Overview

So I have pulled out a document from my database. Inside is a nested collection of objects. Each of the objects inside this nested collection has an '_id' attribute. I want to find one on these objects specifically by its '_id' using Javascript.


Example

/


Alternative Example

/


Questions

  1. Is my example the best way of achieving this?
  2. Will this block in Node.js?

Overview

So I have pulled out a document from my database. Inside is a nested collection of objects. Each of the objects inside this nested collection has an '_id' attribute. I want to find one on these objects specifically by its '_id' using Javascript.


Example

http://jsfiddle/WilsonPage/tNngT/


Alternative Example

http://jsfiddle/WilsonPage/tNngT/3/


Questions

  1. Is my example the best way of achieving this?
  2. Will this block in Node.js?
Share Improve this question edited Feb 7, 2012 at 22:08 Jon Adams 25.2k18 gold badges84 silver badges121 bronze badges asked Dec 2, 2011 at 12:44 wilsonpagewilsonpage 17.6k23 gold badges105 silver badges150 bronze badges 2
  • The "Async Example" isn't async. I think your first example is the standard way to do it, though I'd probably return null rather than false for a not-found. – nnnnnn Commented Dec 2, 2011 at 13:05
  • Checkout an example I made using async.js: jsfiddle/WilsonPage/yJSjP/3 – wilsonpage Commented Dec 2, 2011 at 15:06
Add a ment  | 

5 Answers 5

Reset to default 1

Yes, if you only know a specific value which is contained by one of your objects (which are held in an Array) you need to loop over the whole structure and pare those values.

As you also did right, break the iteration when you found one (return in your example).
So my answer to your first question would be yes, in terms of performance this is the right and best way.

What I don't get is the "Async" example. You just moved the code and changed the structure. Your code is still "blocking" since you're using a normal for-loop to search. If that array would be huge, it would block your node-app for the amount of time the loop needs to finish.

To really make it asynchronously, you would need to get rid of any loop. You would need to loop over the structure with a runway-timer.

var findById = function(collection, _id, cb){
    var coll = collection.slice( 0 ); // create a clone

    (function _loop( data ) {
        if( data._id === _id ) {
            cb.apply( null, [ data ] );
        }
        else if( coll.length ) {
            setTimeout( _loop.bind( null, coll.shift() ), 25 );
        }
    }( coll.shift() ));
};

And then use it like

findById( myCollection, 102, function( data ) {
    console.log('MATCH -> ', data);
});

This technique (which is a simplified example), we are creating an self-invoking anonymous function and we pass in the first array item (using .shift()). We do our parison and if we found the item we are looking for, execute a callback function the caller needs to provide. If we don't have a match but the array still contains elements (check for the .length), we create a timeout of 25ms using setTimeout and call our _loop function again, this time with the next array item, because .shift() gets and removes the first entry. We repeat that until either no items are left or we found the element. Since setTimeout gives other tasks in the JS main thread (on a browser, the UI thread) the chance to do things, we don't block and screw up the whole show.

As I said, this can get optimized. For instance, we can use a do-while loop within the _loop() method and also use Date.now() to do things until we go over the 50ms mark for instance. If we need longer than that, create a timeout the same way and repeat the above described operation again (so its like, do as much operation as possible within 50ms).

I'd pre-sort the array by each item's _id and at least implement a binary search, if not something a little more sophisticated if speed is really an issue.

You could try using binary search, in most cases it's faster than linear search. As jAndy said, you will still block with standard for loop, so take a look at some node asynchronous library. First that falls to my mind is async.js

I messed around with async.js to produce this solution to my problem. I have tried make it a reusable as possible so it is not just locked down to search the '_id' attribute.

My Solution:

http://jsfiddle/WilsonPage/yJSjP/3/

Assuming you can generate unique strings from your _id you could hash them out with js's native object.

findById = (collection, _id, callback, timeout = 500, step = 10000)->
   gen = ->
      hash = {}
      for value, i in collection
         hash[value._id] = value
         unless i % step then yield i
      hash[_id]

   it = gen()
   do findIt = ->
      {done, value} = it.next()
      if done then callback value
      else 
         console.log "hashed #{(value/collection.length*100).toFixed 0}%"
         setTimeout findIt, timeout

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745012084a4606131.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信