how can I rewrite my mongoose query after splitting data from one model into two?

873 views Asked by At

In my application I store comments. Previously my model for that looked like this:

var CommentsSchema = new Schema({
    username: {type: String},
    display_name: {type: String},
    facebook_username: {type: String},
    text_content: {type: String},
    photo_content_url: {type: String},
    hashtags: {type: [String]},
    device_id: {type: String},
    comment_date: {type: Date, default: Date.now},
    friends_only: {type: Boolean, default: false}
}

Each comment - besides storing its details - had also details about the author, e.g. username, facebook_username, device_id from which the comment was added and display_name. There was also a bool flag friends_only based on which I was deciding whether that comment should be visible only to user's facebook friends or to everyone.

Construction of the node.js/mongoose query for fetching all comments looked like this:

commentsRoutes.post('/friends', function (req, res) {
    var friends = req.body.friends;
    var publicComments = req.body.publicComments;

    var hashtagsInput = req.body.hashtags;

    var startDate = req.body.startDate;
    var endDate = req.body.endDate;

    var query= {};
    query.$and = [];

    // and condition on start date
    if(startDate != undefined) {
        var startDate = new Date(req.param('startDate'));
        var endDate = new Date(req.param('endDate'));
        query.$and.push({"comment_date":{$gte: startDate}});
        query.$and.push({"comment_date":{$lte: endDate}});
    }

    // and condition on hastags
    if (hashtagsInput != undefined) {
        var hashtags = hashtagsInput.split(",");
        query.$and.push({"hashtags":{$in: hashtags}});
    }

    // creating a OR condition for facebook friends and public flag
    var friend_query = {};
    friend_query.$or = [];

    if (friends != undefined) {
        var friendsSplit = friends.split(",");
        friend_query.$or.push({"facebook_username":{$in: friendsSplit}});
    }

    if (publicComments != undefined && publicComments === "true") {
        friend_query.$or.push({friends_only: false});
    }

    //Merging facebook friend condition with other condition with AND operator.
    query.$and.push(friend_query);

    var finalQuery = Comment.find(query)

With the code above user could fetch content posted by his friends (that was set either to public or private) and all other public content (from everyone else).

I've decided to change all of that and split the data into two models. After changing it I have:

var CommentsSchema = new Schema({
    user_id: {type: String, required: true, ref: 'users' },
    text_content: {type: String},
    photo_content_url: {type: String},
    hashtags: {type: [String]},
    comment_date: {type: Date, default: Date.now},
    friends_only: {type: Boolean, default: false},
    device_id: {type: String}
}

and

var UsersSchema = new Schema({
    username: {type: String},
    facebook_username: {type: String},
    display_name: {type: String}
}

Now, when I want to keep the old functionality, I need to modify the code responsible for creating the query. I could merge two queries with async, or the other way is to use mongoose .populate option. I decided to go with the second choice, so now I need to move the code responsible for creating or query to the match part of populate function:

...
var finalQuery = Comment.find(query)

finalQuery.populate({path: 'user_id', 
    select: 'facebook_username display_name username',
    match: {

}});

I don't know how to do it. Can you help me with that?

1

There are 1 answers

0
Vinay Pandya On

First, i suggest you that go with a populate query, if you feel that populate won't give you a data that you need that you can run two queries and merge those results.

for populate, i found the solution from the official doc of mongoose. you can do like this.

var mongoose = require('mongoose')
  , Schema = mongoose.Schema

var personSchema = Schema({
  _id     : Number,
  name    : String,
  age     : Number,
  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
  _creator : { type: Number, ref: 'Person' },
  title    : String,
  fans     : [{ type: Number, ref: 'Person' }]
});

var Story  = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);

Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
  if (err) return handleError(err);
  console.log('The creator is %s', story._creator.name);
  // prints "The creator is Aaron"
});

here is doc link: http://mongoosejs.com/docs/populate.html