Bren Bren - 6 months ago 20
Javascript Question

forEach over cursor

I'm using a nested function to call two methods to duplicate a set of documents. The documents come from two different collections but are linked in by the treeBranches field, as shown below.

Trees collection

{
_id: "tree_1",
treeBranches: ["branch_1","branch_2"],
...
}


Branches collection

{
_id: "branch_1",
branchName: "Branch 1",
...
}
{
_id: "branch_2",
branchName: "Branch 2",
...
}


I don't understand how to get the
_id
of each existing branch document within
branches.forEach
. Right now, when I run this, multiple branch documents are created, but each duplicates the first existing branch regardless of how many exist. How can I edit
var currentBranchId = Branches.findOne({})._id;
to get this
_id
and properly loop over the set?

CODE EDITED TO INCORPORATE ANSWER

Template.Actions.events({
'change .action-selection': function(e) {
e.preventDefault();

var selection = $(e.target).val();

var currentTreeId = this._id;
var branches = Branches.find({_id:{$in:this.treeBranches}});

switch(selection) {
case "tree-repeat":
return Meteor.call('treeRepeat', currentTreeId, function () {
branches.forEach(function(b) {
var currentBranchId = b._id;
Meteor.call('treeBranchesRepeat', currentBranchId, function (branchId) {
});
});
});
break;

}
}
});

Meteor.methods({
treeRepeat: function(currentTreeId) {
check(currentTreeId, String);

var tree = Trees.findOne({_id:currentTreeId}, {fields:{_id:0, treeBranches:0}});

var treeExtended = _.extend(tree, {
treeBranches: [?]//NEED IDS FROM NEW BRANCHES
});

var treeId = Trees.insert(treeExtended);

return {
_id: treeId
};
},
treeBranchesRepeat: function(currentBranchId) {
check(currentBranchId, String);

var branch = Branches.findOne({_id:currentBranchId}, {fields: {_id: 0}});

var branchId = Branches.insert(branch);

return {
_id: branchId
};
}
});

Answer

You can iterate over a cursor with forEach (just like an array) so, for example:

var cursor = Branches.find();
cursor.forEach(function(b){ // b will be a single branch document
  console.log(b._id); // you can get its _id directly
  console.log(b.branchName); // or any other key
});

It makes no sense to do a forEach() over a cursor and then do a findOne inside the loop since forEach() will pass each object in turn to the anonymous function.

It's not clear from your question how you decide which branches belong to which tree.

If I wanted to create a denormalized copy of your original Trees collection I might do the following:

var treeCursor = Trees.find();
treeCursor.forEach(function(tree){
  DenormalizedTrees.insert({_id: tree._id}); // reuse the same _id
  tree.treeBranches.forEach(function(id){ // now iterate over the array of branch ids
    var branch = Branches.findOne(id);
    DenormalizedTrees.update(tree._id,{ $push: { treeBranches: branch }});
  });
});
Comments