从子集合中搜索包含来自父子集合的关键字

Posted

技术标签:

【中文标题】从子集合中搜索包含来自父子集合的关键字【英文标题】:search from child collection contains the keyword from parent and child collection 【发布时间】:2021-07-20 11:21:21 【问题描述】:

我在使用父子关系集合从数据库获取数据时遇到问题。 这是我的收藏结构—— -邮政 ---发布布:品牌集合中的品牌ID -----品牌

现在我正在从 post 和 postcloth 中获取数据,如果 postcloth 和 brand 中的任何键匹配,则从 postcloth 和品牌表中进行关键字搜索。直到发布布料它与关键字搜索或条件一起工作正常,现在我还需要从品牌搜索并返回结果,如果关键字也包含在品牌中。 这是我的案例--

    返回的数据:如果任何 post_cloths 键与搜索的关键字匹配 返回的数据:如果任何 post_cloths 键与关键字匹配或带有品牌名称的查找与关键字匹配 返回的数据:如果 post_cloths 中的所有键都与关键字不匹配,但带有品牌名称的查找与关键字匹配 数据未返回:如果 post_cloths 中没有与关键字匹配的键,并且查找品牌名称与关键字不匹配

这是我的代码:

var page = 0;
if (req.query.page >= 0) 
    page = req.query.page;

let filter =  'totalCloth':  $gte: 1  ;
if (req.query.user != null && req.query.user != '') 
    filter.createdBy = ObjectID(req.query.user);

console.log(filter);
var searchQuery = [];
var brandSearchQuery = [];
if (req.query.keyword != null && req.query.keyword != '') 
    console.log(req.query.keyword);
    keyword = req.query.keyword;
    searchQuery = [
        
            $regexFind: 
                input: '$category',
                regex: new RegExp(keyword),
                options: 'i',
            ,
        ,
        
            $regexFind: 
                input: '$color',
                regex: new RegExp(keyword),
                options: 'i',
            ,
        ,
        
            $regexFind: 
                input: '$country',
                regex: new RegExp(keyword),
                options: 'i',
            ,
        ,
        
            $regexFind: 
                input: '$size',
                regex: new RegExp(keyword),
                options: 'i',
            ,
        ,
        
            $regexFind: 
                input: '$clothMaterial',
                regex: new RegExp(keyword),
                options: 'i',
            ,
        ,
    ];
    brandSearchQuery = [
        
            $regexFind: 
                input: '$name',
                regex: new RegExp(keyword),
                options: 'i',
            ,
        ,
    ];
 else 
    searchQuery = [];
    brandSearchQuery = [];

// get the post details
// PostModel.find(filter).countDocuments().then(countPosts => 
PostModel.aggregate([
    
        $lookup: 
            from: 'post_cloths',
            let:  postId: '$_id' ,
            pipeline: [
                //lookup for brand
                
                    $lookup: 
                        from: 'brands',
                        let:  brandId: '$brandId' ,
                        pipeline: [
                            
                                $match: 
                                    $expr:
                                        
                                            $and:
                                                [
                                                     $eq: ['$_id', '$$brandId'] ,
                                                     $or: brandSearchQuery ,
                                                ],
                                        ,
                                ,
                            ,
                        ],
                        as: 'brand',
                    ,
                ,
                //end of brand lookup
                
                    $match: 
                        $expr: 
                            $and:
                                [
                                     $eq: ['$postId', '$$postId'] ,
                                    
                                        $or: searchQuery,
                                    ,
                                ],
                        ,
                    ,
                ,
                
                    $project: 
                        totalBrands:  $size: '$brand' ,
                    ,
                ,
                
                    $match: 
                        $expr:
                             $or: [ $match:  totalBrands:  $gte: 1   ] ,
                    ,
                ,
            ],
            as: 'postCloth',
        ,
    ,
    
        $project: 
            image: 1,
            createdAt: 1,
            createdBy: 1,
            mediaUrl: 
                $concat: [process.env.PROJECT_URL + '/files/', '$image'],
            ,
            totalCloth:  $size: '$postCloth' ,
        ,
    ,
    //check for post cloth object if length is greater than equals to 1
    
        $match: filter,
    ,

     $skip: 12 * page ,
     $limit: 12 ,
     $sort:  createdAt: -1  ,
]).exec(function(err, post) 
    return apiResponse.successResponseWithData(res, 'Successful', post);
);

我正在正确获取数据,但不是在从品牌搜索时。请建议我们如何从给定的案例中搜索数据。有简单的关键字搜索。

提前致谢

【问题讨论】:

发布所有集合和预期结果的一些示例文档。 这个太难理解了,能举例说明一下吗? 【参考方案1】:

问题在于你是主要的$lookup 的管道:

首先你从brand$lookup开始,我假设它是有效的(如果你为你的集合提供架构,那将很容易验证),但是在$lookup之后你这样做:


    $match: 
        $expr:
            
                $and:
                    [
                         $eq: ['$postId', '$$postId'] ,
                        
                            $or: searchQuery,
                        ,
                    ],
            ,
    ,
,

这意味着如果searchQuery 失败,即使品牌存在,文档也会被过滤掉,您应该将其更改为:


    $match: 
        $expr:
            
                $and:
                    [
                         $eq: ['$postId', '$$postId'] ,
                        
                            $or: [
                                
                                    $or: searchQuery
                                ,
                                
                                    $gt: [$size: "$brand", 0]
                                
                            ],
                        ,
                    ],
            ,
    ,
,

现在这也将匹配在 brand 字段中包含任何品牌的文档,这意味着品牌与嵌套的 $lookup 匹配,然后您可以删除接下来检查品牌大小的 2 个阶段。

我还建议您将postId$eq 移动到$lookup 的开头,这将极大地提高性能,在所有更改之后整个管道看起来像这样:

PostModel.aggregate([
    
        $lookup: 
            from: 'post_cloths',
            let:  postId: '$_id' ,
            pipeline: [
                
                    $match:  $eq: ['$postId', '$$postId'] ,
                ,
                
                    $lookup: 
                        from: 'brands',
                        let:  brandId: '$brandId' ,
                        pipeline: [
                            
                                $match: 
                                    $expr:
                                        
                                            $and:
                                                [
                                                     $eq: ['$_id', '$$brandId'] ,
                                                     $or: brandSearchQuery ,
                                                ],
                                        ,
                                ,
                            ,
                        ],
                        as: 'brand',
                    ,
                ,
                
                    $match: 
                        $expr: 
                            $and:
                                [

                                    
                                        $or: [
                                            
                                                $or: searchQuery,
                                            ,
                                            
                                                $gt: [ $size: '$brand' , 0],
                                            ,
                                        ],
                                    ,
                                ],
                        ,
                    ,
                ,
            ],
            as: 'postCloth',
        ,
    ,
    
        $project: 
            image: 1,
            createdAt: 1,
            createdBy: 1,
            mediaUrl: 
                $concat: [process.env.PROJECT_URL + '/files/', '$image'],
            ,
            totalCloth:  $size: '$postCloth' ,
        ,
    ,
    
        $match: filter,
    ,
     $skip: 12 * page ,
     $limit: 12 ,
     $sort:  createdAt: -1  ,
])

【讨论】:

以上是关于从子集合中搜索包含来自父子集合的关键字的主要内容,如果未能解决你的问题,请参考以下文章

如何仅使用一个关键字搜索 MongoDB 集合中的所有键

如何快速搜索基于字符串的键/值集合

MongoDB:用于搜索性能的嵌套值与单独的集合 - 数据库模式设计

Java 集合框架

Java中的集合框架

如何检查 MongoDB 数据库中的所有集合以查找特定关键字?