2

I'm trying to group items by tag. But I do not get what exactly I want to do.

There is schema Item (_id, name, tags) with tags is array of tags_id ( was referenced from Tag schema )

Item = new Schema({
    id: Schema.ObjectId,
    name: String,
    tags: [ { type: Schema.ObjectId, ref: 'Tag' }]
});

Tag = new Schema({
    id: Schema.ObjectId,
    name: String
});

This is what I have done so far:

Item.aggregate([
        {
          "$lookup": {
            "from": Tag.collection.name,
            "let": { "tags": "$tags" },
            "pipeline": [
              {
                "$match": {
                  "$expr": { "$in": ['$_id', '$$tags'] }
                }
              },
              {
                "$project": {
                  "_id": 1,
                  "name": 1
                }
              }
            ],
            "as": 'tags'
          }
        },
        {
          "$group": {
            "_id": "$tags._id",
            "items": {
              "$push": {
                "id": "$_id",
                "name": "$name",
              }
            }
          }
        }
      ]);

This is what I get

{
  "data": [
    {
      "_id": [
        "5eb95e8dcae79713f1de0a27"
      ],
      "items": [
        {
          "id": "5eb95e9fcae79713f1de0a28",
          "name": "My Item 1"
        }
      ]
    },
    {
      "_id": [
        "5eb9564dc4317411fe79e1bf"
      ],
      "items": [
        {
          "id": "5eb95b1430f138131ed90f4f",
          "name": "My Item 2"
        },
        {
          "id": "5eb95ed0cae79713f1de0a29",
          "name": "My Item 3"
        }
      ]
    }
  ]
}

I would like to get the name of each tag, and not only the _id possibly not within an array. Below the result that I would like to receive:

{
  "data": [
    {
      "_id": "5eb95e8dcae79713f1de0a27",
      "name": "My Tag name 1",
      "items": [
        {
          "id": "5eb95e9fcae79713f1de0a28",
          "name": "My Item 1"
        }
      ]
    },
    {
      "_id": "5eb9564dc4317411fe79e1bf",
      "name": "My Tag name 2",
      "items": [
        {
          "id": "5eb95b1430f138131ed90f4f",
          "name": "My Item 2"
        },
        {
          "id": "5eb95ed0cae79713f1de0a29",
          "name": "My Item 3"
        }
      ]
    }
  ]
}

What am I doing wrong?

Anthony Lee
  • 223
  • 1
  • 6
  • 14

1 Answers1

1

One way to to this is to add the tag-name to your $group operator:

...
{
    "$group": {
        "_id": "$tags._id",
        "tagName": {$first: "$tags.name"},
        "items": {
            "$push": {
                "id": "$_id",
                "name": "$name",
            }
        }
    }
}
...

Note that this will take the first matching entry for each group. Another option would be to use $replaceRoot and the $mergeObjects operator, like it was done here.

eol
  • 23,236
  • 5
  • 46
  • 64