Mongodb $lookup to retrieve menu and sub menu as a sub document array

Viewed 151

Looks like an old question, but I think the schema is a slight different and I'm not sure if this is the proper schema definition, but I want it this way.

import { Schema, model } from 'mongoose';
import * as mongoose from 'mongoose';
const ObjectId = mongoose.Schema.Types.ObjectId;

const MenuSchema = new Schema({
  parent: { 
    type: Schema.Types.ObjectId,
    ref: 'Menu', required: true, default: null },
  url: {
    type: String,
    required: true,
    unique: true,
  },
  title: {
    en: {
      type: String,
      required: true,
    },
    ar: {
      type: String,
      required: true,
    },
  },
  type: {
    // internal or external
    type: String,
    required: false,
    default: 'internal',
  },
  displayOrder: { type: Number, required: true, default: 0 },
  image: {
    // For icon
    type: Object,
  },
  createdAt: { type: Date, default: Date.now },
  createdBy: { type: ObjectId, ref: 'User' },
  updatedAt: { type: Date, default: Date.now },
  updatedBy: { type: ObjectId, ref: 'User' },
});

My data are like below

{ 
    "_id" : ObjectId("5f97be37bf401d75ed7de8a8"), 
    "parent" : null, 
    "displayOrder" : NumberInt(0), 
    "image" : null, 
    "title" : {
        "en" : "Home", 
        "ar" : "الصفحة الرئيسية"
    }, 
    "url" : "/"
}
{ 
    "_id" : ObjectId("5f97eca04b076b2b8cb5646b"), 
    "type" : "internal", 
    "url" : "/about", 
    "title" : {
        "en" : "About", 
        "ar" : "حول"
    }, 
    "createdAt" : ISODate("2020-10-27T09:47:12.396+0000"), 
    "updatedAt" : ISODate("2020-10-27T09:47:12.396+0000"), 
    "__v" : NumberInt(0), 
    "displayOrder" : NumberInt(1), 
    "image" : null, 
    "parent" : null
}
{ 
    "_id" : ObjectId("5f99492da0c7207dfb13aa03"), 
    "type" : "internal", 
    "url" : "/our-partners", 
    "title" : {
        "en" : "Our Partners", 
        "ar" : "شركاؤنا"
    }, 
    "createdAt" : ISODate("2020-10-28T10:34:21.353+0000"), 
    "updatedAt" : ISODate("2020-10-28T10:34:21.354+0000"), 
    "__v" : NumberInt(0), 
    "image" : null, 
    "displayOrder" : NumberInt(8), 
    "parent" : null
}
{ 
    "_id" : ObjectId("5f9a7971f8443ecbdb787c4a"), 
    "parent" : null, 
    "type" : "internal", 
    "displayOrder" : NumberInt(2), 
    "url" : "/services", 
    "title" : {
        "en" : "Services", 
        "ar" : "خدمات"
    }, 
    "createdAt" : ISODate("2020-10-29T08:12:33.366+0000"), 
    "updatedAt" : ISODate("2020-10-29T08:12:33.366+0000"), 
    "__v" : NumberInt(0), 
    "image" : null
}
{ 
    "_id" : ObjectId("5f9a93f3dc3f16e672d9e84e"), 
    "parent" : null, 
    "type" : "internal", 
    "displayOrder" : NumberInt(3), 
    "url" : "products", 
    "title" : {
        "en" : "Products", 
        "ar" : "منتجات"
    }, 
    "createdAt" : ISODate("2020-10-29T10:05:39.551+0000"), 
    "updatedAt" : ISODate("2020-10-29T10:05:39.551+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b7a9c95213c7e3736e63e"), 
    "parent" : null, 
    "type" : "internal", 
    "displayOrder" : NumberInt(4), 
    "url" : "projects", 
    "title" : {
        "en" : "Projects", 
        "ar" : "المشاريع"
    }, 
    "createdAt" : ISODate("2020-10-30T02:29:48.863+0000"), 
    "updatedAt" : ISODate("2020-10-30T02:29:48.863+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b7aa395213c7e3736e63f"), 
    "parent" : null, 
    "type" : "internal", 
    "displayOrder" : NumberInt(5), 
    "url" : "gallery", 
    "title" : {
        "en" : "Gallery", 
        "ar" : "صالة عرض"
    }, 
    "createdAt" : ISODate("2020-10-30T02:29:55.845+0000"), 
    "updatedAt" : ISODate("2020-10-30T02:29:55.845+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b7af995213c7e3736e640"), 
    "parent" : null, 
    "type" : "internal", 
    "displayOrder" : NumberInt(6), 
    "url" : "downloads", 
    "title" : {
        "en" : "Downloads", 
        "ar" : "التحميلات"
    }, 
    "createdAt" : ISODate("2020-10-30T02:31:21.205+0000"), 
    "updatedAt" : ISODate("2020-10-30T02:31:21.205+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b7b6095213c7e3736e641"), 
    "parent" : null, 
    "type" : "internal", 
    "displayOrder" : NumberInt(7), 
    "url" : "contact", 
    "title" : {
        "en" : "Contact", 
        "ar" : "اتصل"
    }, 
    "createdAt" : ISODate("2020-10-30T02:33:04.071+0000"), 
    "updatedAt" : ISODate("2020-10-30T02:33:04.071+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b8459391ab38846326a43"), 
    "parent" : "5f97eca04b076b2b8cb5646b", 
    "type" : "internal", 
    "displayOrder" : NumberInt(0), 
    "url" : "about", 
    "title" : {
        "en" : "Corporate Overview", 
        "ar" : "لمحة عن الشركة"
    }, 
    "createdAt" : ISODate("2020-10-30T03:11:21.048+0000"), 
    "updatedAt" : ISODate("2020-10-30T03:11:21.048+0000"), 
    "__v" : NumberInt(0), 
    "image" : null
}
{ 
    "_id" : ObjectId("5f9b8bb8391ab38846326a44"), 
    "parent" : "5f97eca04b076b2b8cb5646b", 
    "type" : "internal", 
    "displayOrder" : NumberInt(1), 
    "url" : "md-message", 
    "title" : {
        "en" : "Md's Message", 
        "ar" : "رسالة د"
    }, 
    "createdAt" : ISODate("2020-10-30T03:42:48.341+0000"), 
    "updatedAt" : ISODate("2020-10-30T03:42:48.341+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b8c0e391ab38846326a45"), 
    "parent" : "5f97eca04b076b2b8cb5646b", 
    "type" : "internal", 
    "displayOrder" : NumberInt(2), 
    "url" : "certificates", 
    "title" : {
        "en" : "Certificates", 
        "ar" : "الشهادات"
    }, 
    "createdAt" : ISODate("2020-10-30T03:44:14.876+0000"), 
    "updatedAt" : ISODate("2020-10-30T03:44:14.876+0000"), 
    "__v" : NumberInt(0), 
    "image" : null
}
{ 
    "_id" : ObjectId("5f9b8c4e391ab38846326a46"), 
    "parent" : "5f9a7971f8443ecbdb787c4a", 
    "type" : "internal", 
    "displayOrder" : NumberInt(0), 
    "url" : "before-sale-service", 
    "title" : {
        "en" : "Before Sale Service", 
        "ar" : "خدمة ما قبل البيع"
    }, 
    "createdAt" : ISODate("2020-10-30T03:45:18.489+0000"), 
    "updatedAt" : ISODate("2020-10-30T03:45:18.489+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b8c98391ab38846326a47"), 
    "parent" : "5f9a7971f8443ecbdb787c4a", 
    "type" : "internal", 
    "displayOrder" : NumberInt(1), 
    "url" : "installation", 
    "title" : {
        "en" : "Installation", 
        "ar" : "التركيب"
    }, 
    "createdAt" : ISODate("2020-10-30T03:46:32.943+0000"), 
    "updatedAt" : ISODate("2020-10-30T03:46:32.943+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b8ccb391ab38846326a48"), 
    "parent" : "5f9a7971f8443ecbdb787c4a", 
    "type" : "internal", 
    "displayOrder" : NumberInt(3), 
    "url" : "maintenance", 
    "title" : {
        "en" : "Maintenance", 
        "ar" : "اعمال صيانة"
    }, 
    "createdAt" : ISODate("2020-10-30T03:47:23.943+0000"), 
    "updatedAt" : ISODate("2020-10-30T03:47:23.944+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b8d04391ab38846326a49"), 
    "parent" : "5f9a7971f8443ecbdb787c4a", 
    "type" : "internal", 
    "displayOrder" : NumberInt(3), 
    "url" : "repairs-modernization", 
    "title" : {
        "en" : "REPAIRS AND MODERNIZATION", 
        "ar" : "الإصلاح والتحديث"
    }, 
    "createdAt" : ISODate("2020-10-30T03:48:20.958+0000"), 
    "updatedAt" : ISODate("2020-10-30T03:48:20.958+0000"), 
    "__v" : NumberInt(0), 
    "image" : null
}
{ 
    "_id" : ObjectId("5f9b90180d34dd99a22729fc"), 
    "parent" : "5f9b7aa395213c7e3736e63f", 
    "type" : "internal", 
    "displayOrder" : NumberInt(0), 
    "url" : "image-gallery", 
    "title" : {
        "en" : "Image Gallery", 
        "ar" : "معرض الصور"
    }, 
    "createdAt" : ISODate("2020-10-30T04:01:28.652+0000"), 
    "updatedAt" : ISODate("2020-10-30T04:01:28.652+0000"), 
    "__v" : NumberInt(0)
}
{ 
    "_id" : ObjectId("5f9b903a0d34dd99a22729fd"), 
    "parent" : "5f9b7aa395213c7e3736e63f", 
    "type" : "internal", 
    "displayOrder" : NumberInt(1), 
    "url" : "video-gallery", 
    "title" : {
        "en" : "Video Gallery", 
        "ar" : "معرض الفيديو"
    }, 
    "createdAt" : ISODate("2020-10-30T04:02:02.999+0000"), 
    "updatedAt" : ISODate("2020-10-30T04:02:02.999+0000"), 
    "__v" : NumberInt(0)
}

My Query to retrieve the parent menu (with parent: null) with childs (parent: someid) is below

db.getCollection("menus").aggregate([
{
    $match: {
         'parent': null   
    }
},
{
    $lookup: {
        from: 'menus',
        localField: '_id',
        foreignField: 'parent',
        as: 'childs'
    }
}
])

But my childs sub document array from the above query is empty.

{ 
    "_id" : ObjectId("5f97be37bf401d75ed7de8a8"), 
    "parent" : null, 
    "displayOrder" : NumberInt(0), 
    "image" : null, 
    "title" : {
        "en" : "Home", 
        "ar" : "الصفحة الرئيسية"
    }, 
    "url" : "/", 
    "childs" : [

    ]
}
{ 
    "_id" : ObjectId("5f97eca04b076b2b8cb5646b"), 
    "type" : "internal", 
    "url" : "/about", 
    "title" : {
        "en" : "About", 
        "ar" : "حول"
    }, 
    "createdAt" : ISODate("2020-10-27T09:47:12.396+0000"), 
    "updatedAt" : ISODate("2020-10-27T09:47:12.396+0000"), 
    "__v" : NumberInt(0), 
    "displayOrder" : NumberInt(1), 
    "image" : null, 
    "parent" : null, 
    "childs" : [

    ]
}
{ 
    "_id" : ObjectId("5f99492da0c7207dfb13aa03"), 
    "type" : "internal", 
    "url" : "/our-partners", 
    "title" : {
        "en" : "Our Partners", 
        "ar" : "شركاؤنا"
    }, 
    "createdAt" : ISODate("2020-10-28T10:34:21.353+0000"), 
    "updatedAt" : ISODate("2020-10-28T10:34:21.354+0000"), 
    "__v" : NumberInt(0), 
    "image" : null, 
    "displayOrder" : NumberInt(8), 
    "parent" : null, 
    "childs" : [

    ]
}
{ 
    "_id" : ObjectId("5f9a7971f8443ecbdb787c4a"), 
    "parent" : null, 
    "type" : "internal", 
    "displayOrder" : NumberInt(2), 
    "url" : "/services", 
    "title" : {
        "en" : "Services", 
        "ar" : "خدمات"
    }, 
    "createdAt" : ISODate("2020-10-29T08:12:33.366+0000"), 
    "updatedAt" : ISODate("2020-10-29T08:12:33.366+0000"), 
    "__v" : NumberInt(0), 
    "image" : null, 
    "childs" : [

    ]
}
{ 
    "_id" : ObjectId("5f9a93f3dc3f16e672d9e84e"), 
    "parent" : null, 
    "type" : "internal", 
    "displayOrder" : NumberInt(3), 
    "url" : "products", 
    "title" : {
        "en" : "Products", 
        "ar" : "منتجات"
    }, 
    "createdAt" : ISODate("2020-10-29T10:05:39.551+0000"), 
    "updatedAt" : ISODate("2020-10-29T10:05:39.551+0000"), 
    "__v" : NumberInt(0), 
    "childs" : [

    ]
}

I want to achieve my result like below with parent list and sub menus as a child documents. Currently my child array is empty with the above query. Looks like simple thing, but I am finding it hard. Please help.

[
  {
    "_id": "5f97be37bf401d75ed7de8a8",
    "parent": null,
    "displayOrder": 0,
    "image": null,
    "title": {
      "en": "Home",
      "ar": "الصفحة الرئيسية"
    },
    "url": "/",
    "childs": []
  },
  {
    "_id": "5f97eca04b076b2b8cb5646b",
    "type": "internal",
    "url": "/about",
    "title": {
      "en": "About",
      "ar": "حول"
    },
    "createdAt": "2020-10-27T09:47:12.396Z",
    "updatedAt": "2020-10-27T09:47:12.396Z",
    "__v": 0,
    "displayOrder": 1,
    "image": null,
    "parent": null,
    "childs" : [
        { 
            "_id" : "5f9b8459391ab38846326a43", 
            "parent" : "5f97eca04b076b2b8cb5646b", 
            "type" : "internal", 
            "displayOrder" : 0, 
            "url" : "about", 
            "title" : {
                "en" : "Corporate Overview", 
                "ar" : "لمحة عن الشركة"
            }, 
            "createdAt" : ISODate("2020-10-30T03:11:21.048+0000"), 
            "updatedAt" : ISODate("2020-10-30T03:11:21.048+0000"), 
            "__v" : 0, 
            "image" : null
        },
        { 
            "_id" : "5f9b8c0e391ab38846326a45", 
            "parent" : "5f97eca04b076b2b8cb5646b", 
            "type" : "internal", 
            "displayOrder" : 1, 
            "url" : "certificates", 
            "title" : {
                "en" : "Certificates", 
                "ar" : "الشهادات"
            }, 
            "createdAt" : ISODate("2020-10-30T03:44:14.876+0000"), 
            "updatedAt" : ISODate("2020-10-30T03:44:14.876+0000"), 
            "__v" : 0, 
            "image" : null
        },
        ...  
    ]
  },
  
]
1 Answers

Your parent field in schema is defined as type: Schema.Types.ObjectId, but in database you have all as string. That's one inconsistency.

To resolve your issue, you just need to replace all parent fields' type from string to ObjectId as $lookup uses equality match and string with ObjectId are not equal.

So, for example, one of your documents should look like this instead:

{ 
    "_id" : ObjectId("5f9b8bb8391ab38846326a44"),
    "parent" : ObjectId("5f97eca04b076b2b8cb5646b"),
    "type" : "internal",
    "displayOrder" : NumberInt(1),
    "url" : "md-message",
    "title" : {
        "en" : "Md's Message",
        "ar" : "رسالة د"
    },
    "createdAt" : ISODate("2020-10-30T03:42:48.341+0000"),
    "updatedAt" : ISODate("2020-10-30T03:42:48.341+0000"),
    "__v" : NumberInt(0)
}

Tested locally and can confirm this works.

Related