1

I will start with a small description of the result I want to get:

Let's imagine we have a collection called "Elements" which contains the 4 documents: 'a','b','c' and 'd'. I want to iterate over "Elements" and insert in a new collection called "Queries" the pairs :

(a,b);(a,c);(a,d);(b,a);(b,c)...(d,a);(d,b);(d,c). => which means "Queries" will contain (in this example) 4*3 = 12 pairs of elements (documents) at the end.

Here is the code I'm using (it's a method in meteor server triggered by a click on a button):

'Queries': function() {
    var allElements = Elements.find();
    allElements.forEach(function(myLeftElement){ //First forEach
        allElements.forEach(function(myRightElement){// Nested forEach
            if(myLeftElement._id !== myRightElement._id){
                Queries.insert( {myLeftElement : myLeftElement._id, myRightElement : myRightElement._id} );
            }
        }); //End Of nested forEach
    }); //End Of First forEach
}

In fact it works only for the first "myLeftElement" with all other elements "myRightElement" but stops there: it inserts, into "Queries" collection, the pairs: [(a,b);(a,c) and (a,d)] and then stops.

Since I am a beginner in web developement in general and in using Meteor in particular, I am seeking for your help.

1) I need to understand why once the nested cursor method "forEach" stops, the whole function stops.

2) How can I improve the code to get the result I really want: to every element of my collection "myLeftElement" there is a forEach method that creates pairs with all other elements "myRightElement". And then moves to the next "myLeftElement" and do the same till the end.

Thanks,

Paulo Alexandre
  • 600
  • 1
  • 8
  • 17
AZAN
  • 13
  • 4

2 Answers2

0

Here is a working example of iterating over an Array with vanilla JavaScript that gets the expected result:

var elements = ['a', 'b', 'c', 'd'];

var result = [];

elements.forEach(function(item) {
  // Create a copy of the current array to work with
  var elements_copy = elements.slice(0);
  var temp_array = [];

  /*
  Delete the current `item` from the array since
  we don't want duplicate 'a:a' items in the array.
  IMPORTANT: There are better ways of doing this,
  see: http://stackoverflow.com/questions/3954438/remove-item-from-array-by-value
  */
  elements_copy.splice(elements_copy.indexOf(item), 1);

  elements_copy.forEach(function(child_item) {
    temp_array.push(item + "," + child_item);
  });

  result.push(temp_array);
});

console.log(result);

You'll need to make sure you open the Console in the Developer Tools to see the result.

When you're starting out I recommend getting working scenarios with the least complexity -- like here where I removed Meteor and Mongo out of the picture -- to ensure that your logic is sound then working in the rest from there.

So, to answer your questions directly:

  1. Unsure of why it is stopping as I'm unable to recreate
  2. Example provided should suffice -- but I'm sure there is a better way

Hope that helps!

cynicaljoy
  • 1,787
  • 1
  • 16
  • 24
  • A lot of thanks to @cynicaljoy for your answer, although it doesn't directly solve my problem, but it got me inspired and I was able then to find the one working and satisfying solution. – AZAN Dec 29 '15 at 09:36
0

The @cynicaljoy's answer inspired me in two ways:

  • using arrays
  • and a better way of deleting duplicate 'a:a' items in the arrays (by visiting the link he provided).

So thanks a lot.

Now after taking the necessary modifications, here is one solution that actually works fine using Meteor and Mongodb codes:

'Queries' : function() {

var allElements = Elements.find().map(function(item){return item._id} ); /* this returns an array of item._id of all elements*/
var totalItems = allElements.length;
var itemsCounter = 0;
var withoutLeftItem;
   while(itemsCounter < totalItems){
      withoutLeftItem=_.without(allElements,allElements[itemsCounter] ); /*The function _.without(array, *items) used in underscore.js returns array with specified items removed */    
      withoutLeftItem.forEach(function(myRightElement){
         Queries.insert( {myLeftElement : allElements[itemsCounter], myRightElement : myRightElement} );
      });
   itemsCounter++;
   }
 }

I am still curious to understand why the solution presented in the question was not working as it was supposed and also to see an optimized code in terms of memory usage.

Hope this helps other people. Thanks all

AZAN
  • 13
  • 4
  • I actually have a question about the code listed here. It creates 2 arrays : "allElements" and "withoutLeftItem". At the end of code execution, they are still there. Now in a production environement, should I explicitely delete them at the end of the exection? – AZAN Dec 29 '15 at 10:51