2

I appreciate some help. I'm doing an api rest with express and mongodb (v3.4.4), using mongoose (v4.10.5). I need to do an aggregation operation, but I do not deal with it. I show you some code. The models (it has more properties, but I have left it simple):

const CategoryModel = mongoose.model('Category', new Schema({
    slug: { type: String, unique: true, lowercase: true, index: true },
    description: String
}));

const MyModel = mongoose.model('MyModel', new Schema({
    category: { type: Schema.Types.ObjectId, ref: 'Category' },
    other: [{ type: Schema.Types.ObjectId, ref: 'Other' }], 
    times_count: { type: Number, default: 0 }
}));

Important, I'm interested in populate category field of MyModel, not other field.

Suppose Category and MyModel has certain records well formed. The request:

MyModel.aggregate([
  {
    $group : {
      _id : '$_id',
      times: { $sum: '$times_count' }
    }
  },
  {
    $limit: 5
  }
]).limit(5).exec().then((data) => {
  console.log(data);
}).catch((err) => {
  console.error(err);
});

data is correct, has 5 records, but not include category. Now, I try with:

MyModel.aggregate([
  {
    $group : {
      _id : '$_id',
      times: { $sum: '$times_count' }
    }
  },
  {
    $limit: 5
  },
  {
    $lookup: {
      from: 'Category', // I tried with 'Categories' and 'categories'
      localField: 'category',
      foreignField: '_id',
      as: 'category'
    }
  },
  {
    $unwind: '$category'
  }
]).limit(5).exec().then((data) => {
  console.log(data);
}).catch((err) => {
  console.error(err);
});

Now data is empty. I set mongoose.set('debug', true); and the operations they look right, inclusive the last operation aggregate, but data is empty...

I do not know if I explained well. Obviously there is something that I am not fully understanding. Thanks in advance.

lmfresneda
  • 449
  • 7
  • 18

1 Answers1

4

I get the desired records in objs, the problem is that I only come with the _id and times properties, and I need to populate the category.

That's about right since you didn't explicitedly add the stage to join the other collection.

I've tried adding $project to the aggregation after the $ group but nothing.

In simple terms, $project is for including and excluding new fields using one collection, not joining.

You are looking for $lookup which is for joining one collection with another. When you join a new collection, each document will have a new array field containing the "joined" documents from the other collection.

In your case, your new array field will have one document from the other collection, so you probably want to $unwind also.

MyModel.aggregate([
    {
        $group : {
            _id : '$_id',
            times: { $sum: '$times_count' },
            category: { $first: '$category' }
        }
    },
    /*
    {
        $limit: 5
    },
    */
    {
        $lookup: {
            from: 'Categories',
            localField: 'category',
            foreignField: '_id',
            as: 'category'
        }
    },
    {
        $unwind: '$category'
    }
]).exec(...);

In terms of your initial problem, try uncommenting the 2nd stage above and not using limit(5) in your first example.

Mikey
  • 6,728
  • 4
  • 22
  • 45
  • Thanks, but not working. I tried with `from: 'Category'`, `localField: 'category'` and other combinations, I included `$limit` in array, with & without `$unwind`... In summary, a few tens combinations. Also, why require a cursor? I don't understand. Note that the field I want populate is `category` of `MyModel`, not `_id`. Thanks again. – lmfresneda Aug 22 '17 at 18:50
  • @LuisMiguelF. Ah, you're right it should be `category`. You should not need `cursor()` as shown in my example. I would also set [debug on](http://mongoosejs.com/docs/faq.html#enable_debugging) to see any queries. Edit your question with the category schema. Are you also running MongoDB v3.2 or higher? – Mikey Aug 22 '17 at 19:49
  • Sorry @Mikey, the cursor is my fault, I use Mockgoose instead Mongoose in this test (although I do not know why Mockgoose require a cursor). Now, I use Mongoose only and I will edit my question. Still not working... :( – lmfresneda Aug 22 '17 at 20:50
  • @LuisMiguelF. Check my edit. I believe you need to have a `category` field before joining it with another collection. – Mikey Aug 23 '17 at 00:10
  • Wow! With your edit, and replacing 'Categories' for 'categories' (in lowercase), it works! Thank you so much @Mikey – lmfresneda Aug 23 '17 at 16:09
  • In case someone is interested in the Mockgoose error about the cursor, [here](https://github.com/Mockgoose/Mockgoose/issues/32) the issue and [here](https://stackoverflow.com/a/43456382/8496784) a temporary solution – lmfresneda Aug 23 '17 at 16:29
  • @LuisMiguelF. Awesome! – Mikey Aug 23 '17 at 16:48