Mongodb。用$graphLookup,$reduce &$concat建立分类网址,顺序要正确

问题描述 投票:1回答:1

我试图归档的是以正确的顺序获得一个URL作为文档的父母。

我生成了这个查询。

输入

use('testdb');

db.categories.drop();

db.categories.insertMany([
  { '_id' : 'shoes', 'name' : 'Shoes', 'path' : 'shoes', 'parent': null},
  { '_id' : 'sportshoes', 'name' : 'Sport-Shoes', 'path' : 'sportshoes', 'parent': 'shoes'},
  { '_id' : 'sportshoes-black', 'name' : 'Sportshoes Black', 'path' : 'sportshoes-black', 'parent': 'sportshoes'},
  { '_id' : 'sportshoes-black-m', 'name' : 'Sportshoes Black M', 'path' : 'sportshoes-black-m', 'parent': 'sportshoes-black'},
  { '_id' : 'sportshoes-black-w', 'name' : 'Sportshoes Black W', 'path' : 'sportshoes-black-w', 'parent': 'sportshoes-black'},
]);


db.categories.aggregate( [
  {$match: { _id: 'sportshoes-black-m' } },
   {
      $graphLookup: {
         from: "categories",
         startWith: "$parent",
         connectFromField: "parent",
         connectToField: "_id",
         as: "url"
      }
   },
   {
      $project: {
        "name": 1,
        "url" : {
          $reduce: {
            input: "$url.path",
            initialValue: "",
            in: {
              '$concat': [
              '$$value',
              {'$cond': [{'$eq': ['$$value', '']}, '', '/']}, '$$this']
              }
            }
          }
        }
      }
    ]
  )

产量

[
  {
    _id: 'sportshoes-black-m',
    name: 'Sportshoes Black M',
    url: 'shoes/sportshoes/sportshoes-black'
  }
]

在这个例子中,它的顺序是正确的,但当我试图获取的是 sportshoes-black-w 我得到的顺序是错误的。

输出

[
  {
    _id: 'sportshoes-black-w',
    name: 'Sportshoes Black W',
    url: 'sportshoes-black/sportshoes/shoes'
  }
]
mongodb concatenation concat reduce graphlookup
1个回答
1
投票

所有你要做的是排序的URLS之前,如果任何机会,你使用Mongo v4.4的,该 $function 引入了这个操作符,这个操作符允许应用一个自定义的javascript函数来实现MongoDB查询语言不支持的行为,比如像这样对一个数组进行排序。

db.categories.aggregate([
    {$match: {_id: 'sportshoes-black-m'}},
    {
        $graphLookup: {
            from: "categories",
            startWith: "$parent",
            connectFromField: "parent",
            connectToField: "_id",
            as: "url"
        }
    },
    {
        $addFields: {
            "url": {
                $function: {
                    body: function (urls) {
                        urls.sort((a, b) => a.path > b.path);
                        return urls;
                    },
                    args: ["$url"],
                    lang: "js"
                }
            }
        }
    },
    {
        $project: {
            "name": 1,
            "url": {
                $reduce: {
                    input: "$url.path",
                    initialValue: "",
                    in: {
                        '$concat': [
                            '$$value',
                            {'$cond': [{'$eq': ['$$value', '']}, '', '/']}, '$$this']
                    }
                }
            }
        }
    }
])

遗憾的是,对于以前的Mongo版本来说,这样的功能并不存在,你将不得不使用以下功能 $unwind, $sort 然后 $group 来恢复你想要的结构,由于明显的原因,这是很昂贵的,所以在这种情况下,我建议你只在代码后聚合中进行排序。

© www.soinside.com 2019 - 2024. All rights reserved.