coder14
coder14

Reputation: 223

Meteor get value of the first collection, to find value of the other collection

So I got two collections:

  1. Users, with userId, firstname, surname.
  2. Answers, with answerId, questionId, and user.

The 'user' field in the 'Answers' collection, refers to the userId of the user who answerred the question.

I am able to return the userId from the answers collection, but now I want to use the userId to find the Firstname en surname from the Users collection.

Another solution could be to not insert the userId to the Answers collection, but the firstname and surname. But I also dont know how to achieve this.

I hope you understand my question and I hope that anyone can help me!

Yours, L

Upvotes: 1

Views: 68

Answers (2)

chridam
chridam

Reputation: 103365

You should be able to loop through each answer document in the Answers collection using the forEach() method, find the relevant user document by searching the Users collection for the id, as in the following example:

Answers = new Meteor.Collection("answers");
Users = new Meteor.Collection("users");

if(Meteor.isClient) {
    processed_data = []; 

    Deps.autorun(function (c) {
        console.log('run');
        var cursor = Answers.find({}, { sort: { time: 1 }});
        if (!cursor.count()) return;

        cursor.forEach(function (ans) {
            var user = Users.findOne({ "_id": ans.user }, { "fields": {"firstname": 1, "surname": 1} });
            ans.user = user;
            processed_data.push(ans);
        }); 

        console.log(processed_data);
        c.stop();
    }); 
}

The data will be reactive since when you use Deps.autorun, the entire block in function() {...}, will re-run every time a reactive variable, or document changes, in any way at all (that is updated, removed or inserted), or any other reactive variable change.

As for the other solution where you update the userId in the Answers collection with the actual user document which has the firstname and surname, you can achieve this by way of using the Bulk API operations to do the updates. You can get raw access to the collection and database objects in the npm MongoDB driver through rawCollection() and rawDatabase() methods on Mongo.Collection.

Answers = new Meteor.Collection("answers");
Users = new Meteor.Collection("users");

if (Meteor.isClient) {
    Template.answerlist.helpers({
        answers: function () {
            processed_data = []; 

            Deps.autorun(function (c) {
                console.log('run');
                var cursor = Answers.find({}, { sort: { time: 1 }});
                if (!cursor.count()) return;

                cursor.forEach(function (ans) {
                    var user = Users.findOne({ "_id": ans.user }, { "fields": {"firstname": 1, "surname": 1} });
                    ans.user = user;
                    processed_data.push(ans);
                }); 

                console.log(processed_data);
                c.stop();
            }); 

            return processed_data;
        }
    });

    Template.answerlist.events({
        'click #updateAnswers': function(ev) {
            Meteor.call('updateAnswersUser');
        }
    });

}


if (Meteor.isServer) {
    Meteor.startup(function () {
        Meteor.methods({
            updateAnswersUser: function() {
                var bulkOp = Answers.rawCollection().initializeUnorderedBulkOp(),
                    counter = 0;
                Answers.find({}).forEach(function(ans) {
                    var user = Users.findOne({ "_id": ans.user }, { "fields": {"firstname": 1, "surname": 1} });
                    var changes = {};
                    changes["user"] = user;
                    bulkOp.find({"_id": ans._id}).updateOne({ "$set": changes });

                    counter++;
                    if (counter % 1000 == 0) {
                        // Execute per 1000 operations and re-initialize every 1000 update statements
                        bulkOp.execute(function(e, r) {
                            console.info('r.nMatched', r.nMatched, 'r.nModified', r.nModified);
                        });
                        bulkOp = Answers.rawCollection().initializeUnorderedBulkOp();
                    }
                }); 

                // Clean up queues
                if (counter % 1000 != 0){
                    bulkOp.execute(function(e, r) {
                        console.info('r.nMatched', r.nMatched, 'r.nModified', r.nModified);
                    });
                }
            }
        }); 
    });
}

Upvotes: 1

piscator
piscator

Reputation: 8709

You can get the Firstname and surname fields from the Users collection with this query:

Users.find({_id: userId}, {fields:{Firstname: 1, surname: 1}}).fetch();

userId has to be the value of the user's id in the Answers collection.

I'm assuming this value is corresponding to _id in the Users collection.

Saving the Firstname and surname of the user in each answer would cause unnecessary data duplication.

Upvotes: 0

Related Questions