【问题标题】:Pushing entry into multilevel nested array in MongoDB via mongoose通过 mongoose 将条目推送到 MongoDB 中的多级嵌套数组
【发布时间】:2020-12-30 15:56:23
【问题描述】:

我在后端的 nodejs(express) 中使用猫鼬。我的数组结构有三个级别。在第三层,存在一些文件。但我需要根据用户需求添加任何级别的条目。

   [
   {
   "name": "A folder at",
    "route": "level1_a"
  },
  {
    "name":"Another folder at Level1",
    "route": "level1_b",
    "children":
        [
            {
            "name": "A folder at Level2",
            "route": "level1_b/level2_a",
            "children": 
                [
                    {
                    "name": "A folder at Level3",
                    "route": "level1_b/level2_a/level3_a",
                    "children":
                        [
                            {
                            "name": "A file at last level",
                            "route": "level1_b/level2_a/level3_a/file1"
                            },
                            {
                            "name": "Add a new File",
                            "route":"level1_b/level2_a/level3_a/new_file"
                            }
                        ]
                    },
                    {
                    "name": "Add Folder at Level3",
                    "route":"level1_b/level2_a/new_folder"
                    }
                ]
            },
            {
                "name": "Add Folder at level2",
                "route":"level1_b/new_folder"
            }
        ]
  },
  {
      "name": "Add Folder at Level1",
      "route":"new_folder"
  }
]

现在我必须在指定位置添加一个条目。假设在 level2,我需要添加一个文件夹。为了添加,两个参数从角度发送到后端。这些将是“名称”和“路线”。所以我的条目将有{name: 'Products', route: 'level1_a/products'} 并且类似地应该放置在正确的位置,即在level1_a 的孩子内部。 我的后端有一个架构,如下所示:

const navSchema = mongoose.Schema({
name:{type:String,required:true},
route:{type:String},
children:{
    type: {
    name:{type:String,required:true},
    route:{type:String},
 }}
});
module.exports = mongoose.model('NatItems',navSchema);

API 会是这样的:

router.post('/navlist',(req,res,next)=>{
  const name= req.body.folder;
  const route= req.body.url;
  console.log(folder,url);//it will be required parameters like name: 'Products', route:'level1_a/products'
  //let pathArray = route.split('/'); //if you want you can split the urls in the array

  //Help me write the code here

  res.status(201).json({
    message:"Post added successfully!"
  })
})

请帮助我在数据库中添加条目。我知道 navlist.save() 直接添加一个条目,但我无法以嵌套方式添加条目。

PS:我无法更改数组结构,因为这个数组很容易被 angular 读取并制作了完整的导航菜单!我是第一次在 nodejs 和 mongoose 中工作,所以我我很难用猫鼬函数编写代码。

【问题讨论】:

    标签: javascript node.js mongodb express mongoose


    【解决方案1】:

    对于您提供的场景 ({name: 'Products', route: 'level1_a/products'}),更新语句非常简单,如下所示:

    Model.update(
       { route: "level1_a" }, 
       { $push: { children: {name: 'Products', route: 'level1_a/products'} } })
    

    当传入路线中有两个以上段时,事情会变得有点复杂,例如

    {  "name": "Add a new File", "route":"level1_b/level2_a/level3_a/new_file2" };
    

    在这种情况下,您需要利用 the positional filtered operator 并构建 arrayFilters,您的查询将变为:

    Model.update(
        {  "route": "level1_b"},
        {
            "$push": {
                    "children.$[child0].children.$[child1].children": {
                        "name": "Add a new File",
                        "route": "level1_b/level2_a/level3_a/new_file2"
                    }
                }
            },
        {
            "arrayFilters": [
                {
                    "child0.route": "level1_b/level2_a"
                },
                {
                    "child1.route": "level1_b/level2_a/level3_a"
                }
            ]
        })
    

    所以你需要一个函数来循环路由并构建相应的update 语句以及options

    let obj = {  "name": "Add a new File", "route":"level1_b/level2_a/level3_a/new_file2" };
    
    let segments = obj.route.split('/');;
    let query = { route: segments[0] };
    let update, options = {};
    if(segments.length === 2){
        update = { $push: { children: obj } }
    } else {
        let updatePath = "children";
        options.arrayFilters = [];
        for(let i = 0; i < segments.length -2; i++){
            updatePath += `.$[child${i}].children`;
            options.arrayFilters.push({ [`child${i}.route`]: segments.slice(0, i + 2).join('/') });
        }
        
        update = { $push: { [updatePath]: obj } };
        
    }
    
    console.log('query', query);
    console.log('update', update);
    console.log('options', options);

    所以你可以运行:

    Model.update(query, update, options);
    

    【讨论】:

    • 感谢@mickl 的恰当回答。我完全不知道构建 arrayFilters 的概念。很高兴向您授予赏金 xD !只有一件事,在 if(segments.length === 1) 的情况下,即也可以将一个条目直接放入数组中,我在 if 块 -> {obj.save(); return;} 中使用了以下内容。您能否在这里提出一个更好的替代方案,让我仍然可以使用更新 fn?
    • @SwapnilSourabh 是的,您也需要处理这种情况,只需保存就可以了,好主意!
    猜你喜欢
    • 2019-03-28
    • 2020-08-02
    • 2020-04-02
    相关资源
    最近更新 更多