【问题标题】:Using $graphLookup to traverse a nested data structure in MongoDB使用 $graphLookup 遍历 MongoDB 中的嵌套数据结构
【发布时间】:2020-11-08 00:08:08
【问题描述】:

我有以下架构:

const MenuSchema = new mongoose.Schema({
  name: String,
  type: String,
  children: [{ type: ObjectId, ref: 'Menu' }],
});

还有以下查询:

const res = await Menu.aggregate([
   { $graphLookup: { from: "menus", startWith: "$children", connectToField: "children", connectFromField: "_id", as: "menus" }}
]);

如您所见,菜单模式是一种自引用数据结构,子项存储对同一实体的其他实例的引用,并使用“类型”字段来区分级别。我正在尝试为每个子数组(只是 BSON ID)查找和填充文档并返回结果。

上面的示例似乎已经完成了大部分工作,但是当我访问其中一个已填充的菜单时,它有一个扁平数组中所有已填充子项的列表,它不保留关系结构。

例如,如果我打印出res,我会得到:

[  {
    _id: 5f1212d053e5494bb45f18f3,
    children: [ 5f1212d053e5494bb45f18f1 ],
    name: 'Vodka',
    type: 'Item',
    __v: 0,
    menus: [ [Object], [Object], [Object], [Object] ]
  },
  {
    _id: 5f1212d053e5494bb45f18f4,
    children: [ 5f1212d053e5494bb45f18f3, 5f1212d053e5494bb45f18f2 ],
    name: 'Drinks',
    type: 'Category',
    __v: 0,
    menus: [ [Object], [Object] ]
  },
  {
    _id: 5f1212d053e5494bb45f18f5,
    children: [ 5f1212d053e5494bb45f18f4 ],
    name: 'Main Menu',
    type: 'Menu',
    __v: 0,
    menus: [ [Object] ]
  }
]

但是当我打印出res[1].menus 时,我得到:

[
  {
    _id: 5f1212d053e5494bb45f18f3,
    children: [ 5f1212d053e5494bb45f18f1 ],
    name: 'Vodka',
    type: 'Item',
    __v: 0
  },
  {
    _id: 5f1212d053e5494bb45f18f1,
    children: [ 5f1212d053e5494bb45f18f0 ],
    name: 'Double',
    type: 'Variant',
    __v: 0
  },
  {
    _id: 5f1212d053e5494bb45f18f4,
    children: [ 5f1212d053e5494bb45f18f3, 5f1212d053e5494bb45f18f2 ],
    name: 'Drinks',
    type: 'Category',
    __v: 0
  }
]

这是一个平面数组中的所有孩子。

$graphLookup 是正确的方法,还是我只是用错了?

【问题讨论】:

标签: javascript mongodb mongoose mongodb-query


【解决方案1】:

我不知道你是否还在寻找这个问题的答案,但如果你使用猫鼬,你可以利用populate feature and use it as a middleware

这是一个例子: 假设我想要一个人及其朋友的列表,以及他们的朋友-朋友等。结果应该是这样的:

[
    {
        _id: "abc123",
        name: "John Doe",
        friends: [
            {
                _id: "efg456",
                name: "Foo bar",
                friends: [
                    {
                        _id: "hij789",
                        name: "Jane Doe",
                        friends: [more friends...]
                    }
                ]
            }
        ]
]

在数据库中它们是这样存储的

{_id: "abc123", name: "John Doe", friends: ["efg456"]}
{_id: "efg456", name: "Foo bar", friends: ["hij789"]}
{_id: "hij789", name: "Jane Doe", friends: [more friends...]}

您的架构和中间件将是:

const Person = new Schema<Folder>({
    name: {type: String, required: true},
    friends: [{type: Schema.Types.ObjectId, ref: "person"}],
}, {timestamps: true})

Person.pre("find", function(next) {
    this.populate("friends")
    next()
})

将函数作为中间件添加到find 将使它为找到的每个人运行。这包括 friends 数组中的孩子。

【讨论】:

    猜你喜欢
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2011-09-08
    相关资源
    最近更新 更多