2

Wow, that title is hard to read. OK, I'm stuck on something that should be really simple. I have a schema that looks like:

var mongoose = require('mongoose'),
  Schema = mongoose.Schema,
  TrackedVariableSchema = mongoose.model('TrackedVariable').schema;

var ChallengeSchema = new Schema({
  title: {
    type: String,
    default: '',
    trim: true,
    required: 'Title cannot be blank'
  },
  trackedVariables: [TrackedVariableSchema],
  entryConditions: [{
    trackedVar: {
      type: Schema.ObjectId,
      ref: 'TrackedVariable'
    },
    comparison: {
      type: String,
      default: '=='
    },
    compValue: String
  }]
});

mongoose.model('Challenge', ChallengeSchema);

And, TrackedVariableSchema looks like:

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

var types = 'Boolean String Number'.split(' ');
var TrackedVariableSchema = new Schema({
  label: String,
  type: {
    type: String,
    enum: types,
    default: 'String'
  },
  defaultValue: String
});

mongoose.model('TrackedVariable', TrackedVariableSchema);

Each Challenge object maintains an internal list of TrackedVariables. (A 'TrackedVariable' is just a data definition for a datum that we want to track for that Challenge, but that's not very important.) I would prefer to keep TrackedVariables as an array of subdocs to their parent Challenge. I would prefer not to put them in their own collection.

My example is a little obscure, since these entity names won't make intuitive sense, but hopefully you can see what I am trying to do.

The problem comes when I findById() a single Challenge object, and want to see the label for each TrackedVariable of each Condition. Something like this:

{
  "_id": "A1"
  "title": "Make a Sandwich",
  "trackedVariables": [{
    "_id": "B1",
    "label": "Slices of bread",
    "type": "Number",
    "default": "0"
  }, {
    "_id": "B2",
    "label": "Has peanut butter",
    "type": "Boolean",
    "default": "false"
  }, {
    "_id": "B3",
    "label": "Has jam",
    "type": "Boolean",
    "default": "false"
  }],
  "entryConditions": [{
    "trackedVar": {
      "_id": "B1",
      "label": "Slices of bread",
      "type": "Number",
      "default": "0"
    },
    "comparison": ">=",
    "compValue": "2"
  }, {
    "trackedVar": {
      "_id": "B2",
      "label": "Has peanut butter",
      "type": "Boolean",
      "default": "false"
    },
    "comparison": "==",
    "compValue": "true"
  }, {
    "trackedVar": {
      "_id": "B3",
      "label": "Has jam",
      "type": "Boolean",
      "default": "false"
    },
    "comparison": "==",
    "compValue": "true"
  }]
}

Of course, the TrackedVariables aren't populated, so I get something like:

{
  "_id": "5641adcc918df5901b1e1043",
  "title": "Make a Sandwich"
  "trackedVariables": [{
    "_id": "12345",
    "label": "Slices of bread",
    "type": "Number",
    "default": "0"
  }, {
    "_id": "23456",
    "label": "Has peanut butter",
    "type": "Boolean",
    "default": "false"
  }, {
    "_id": "34567",
    "label": "Has jam",
    "type": "Boolean",
    "default": "false"
  }],
  "entryConditions": [{
    "trackedVar": "B1",
    "comparison": ">=",
    "compValue": "2"
  }, {
    "trackedVar": "B2",
    "comparison": "==",
    "compValue": "true"
  }, {
    "trackedVar": "B3",
    "comparison": "==",
    "compValue": "true"
  }]
}

This won't do, because I need to produce a list that looks like:

Challenge entry requirements:

Entry Conditions for this Challenge
===================================
Slices of bread      >=     2
Has peanut butter    ==     true
Has jam              ==     true

No problem. Just use populate(), right?

That's what I thought, too. And, if TrackedVariables were stored in their own collection (not as internal subdocs to a Challenge), this works just fine. But, nothing I've tried will give me the Challenge object with the TrackedVariable populated for each entryCondition.

I've tried pretty much every permutation of the following that I can think of:

Challenge.findById(id)
  .populate('entryConditions.trackedVar')
  .exec(function(err, challenge) {
  ...
...

No matter what I do along these lines, trackedVar always evaluates to either the id, or to null (depending on what I try). I suspect this has something to do with the fact that, in the response, the trackedVariables collections is already fully populated. And, to duplicate those data in the entryConditions collection, would be ... well ... a duplication.

I'm really stumped with this. Seems like it should be trivial.

Foswick
  • 149
  • 1
  • 3
  • 12
  • No responses yet, so I thought I'd add what I've discovered. So far as I can tell, this can't be done. It seems that populate() doesn't work unless the child document is stored outside the parent document. In places where this is true, I have no problems populating. Still hoping someone comes along with a solution. – Foswick Nov 21 '15 at 17:23
  • this won't work unfortunately - populate only works on "root" elements - see https://github.com/Automattic/mongoose/issues/2772 . But maybe a virtual method can help here - see my answer here: http://stackoverflow.com/a/35850418/4650410 – sebbulon Mar 07 '16 at 17:47

0 Answers0