Day 88 - Query population with refPath works. What went wrong?

I have been delving into Mongoose and Lodash rather heavily in the past few days. A strange thing that I found with Mongoose Query Population was that the dynamic referencing of the model to populate from, to be done using refPath in the Schema, didn’t work for multiple documents. (or so I thought! Read on.)

The same thing worked for a single document. I decided to conduct an isolated test to check if this was a problem, or if we were simply using it wrong. The test worked well, it isn’t a problem with mongoose. (I am still no closer to figuring out what the anomaly in the original use-case was)

This was the javascript for the example:

let db_conn_string = "mongodb://<host>:<port>/<db>";
let options = { user: "<username>", pass: "<password" };

let mongoose = require('mongoose');
mongoose.connect(db_conn_string, options);

console.log("Connected to mongoose");

let util = require('util');
let async = require('async');
let Schema = mongoose.Schema;
let ObjectId = Schema.ObjectId;

var PersonSchema = new Schema({
  name: {
    type: String
  },
  username: {
    type: String,
    required: true,
    unique: true
  }
});

var Person = mongoose.model('Person', PersonSchema);

var p1 = new Person({ ... });
var p2 = new Person({ ... });
var p3 = new Person({ ... });

var people = [p1, p2, p3];

p1.save((err) => { ... });
p1.save((err) => { ... });
p1.save((err) => { ... });

var ChatMessageSchema = new Schema({
  message: {
    type: String
  },
  author: {
    type: ObjectId,
    ref: 'Person'
  }
});

var ChatMessage = mongoose.model('ChatMessage', ChatMessageSchema);

var c1 = new ChatMessage({ ... });
var c2 = new ChatMessage({ ... });
var c3 = new ChatMessage({ ... });
var c4 = new ChatMessage({ ... });

var ReportAbuseSchema = new Schema({
  message: {
    type: String
  },
  resource: {
    type: ObjectId,
    refPath: 'entity'
  },
  entity: {
    type: String // Can be either Person or ChatMessage
  }
});

var ReportAbuse = mongoose.model('ReportAbuse', ReportAbuseSchema);

var r1 = new ReportAbuse({ 
                            message: "report a chat", 
                            resource: "5798...", // This is a comment ID
                            entity: "ChatMessage" 
                        });

var r2 = new ReportAbuse({ 
                            message: "report a person", 
                            resource: "5905...", // This is a PERSON ID
                            entity: "Person" 
                        });

records = [c1, c2, c3, c4, r1, r2];

let iterator = function (record, callback) {
  record.save(function (error) {
    if (error) {
      console.error(error.stack);
      process.exit();
    } else {
      console.log("Saved record!");
      callback();
    }
  });
};

async.each(records, iterator, function (error) {
  if (error) {
    console.log(error.stack);
  } else {
    console.log("SUCCESS!");
  }
});

I ran the script once. Opened the DB and copied over the user IDs to put them in the comment and reportAbuse record creations.

The above code didn’t work as is. There was an extremely weird $author_1 dup error. Now that I look at the code again, I wonder if it is because there are a few parallel save operations happening on the Database. I can’t be sure just yet, more updates to follow in the next few days. (I think)

I ran it just by creating one comment, one person and 2 report abuses. And then querying all the report abuses and asking mongoose to populate resource. It worked as expected.

let query = ReportAbuse.find().populate("resource").lean().exec(...)

POST #88 is OVER