Mongodb $lookup 检索菜单和子菜单作为子文档数组

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

看起来像个老问题,但我认为架构略有不同,我不确定这是否是正确的架构定义,但我希望这样。

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' },
});

我的数据如下

{ 
    "_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)
}

我用子项(父项:someid)检索父菜单(父项:null)的查询如下

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

但是上述查询中我的子文档数组是空的。

{ 
    "_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" : [

    ]
}

我想使用父列表和子菜单作为子文档来实现如下所示的结果。目前我的子数组在上面的查询中是空的。看起来很简单的事情,但我发现很难。请帮忙

[
  {
    "_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
        },
        ...  
    ]
  },
  
]

您的 parent 字段在架构中定义为 type: Schema.Types.ObjectId,,但在数据库中您的所有字段都定义为 string。这是一个不一致。

要解决您的问题,您只需将所有 parent 字段的类型从 string 替换为 ObjectId,因为 $lookup 使用相等匹配,而 stringObjectId 不相等。

因此,例如,您的一份文档应该如下所示:

{ 
    "_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)
}

在本地进行了测试,可以确认此功能有效。