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

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

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

  1. 返回的数据:如果任何 post_cloths 键与搜索的关键字匹配
  2. 返回的数据:如果任何 post_cloths 键与关键字匹配或带有品牌名称的查找与关键字匹配
  3. 返回的数据:如果 post_cloths 中的所有键都与关键字不匹配,但带有品牌名称的查找与关键字匹配
  4. 数据未返回:如果 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);
});

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

提前致谢

【问题讨论】:

  • 发布所有集合和预期结果的一些示例文档。
  • 这个太难理解了,能举例说明一下吗?

标签: node.js mongodb express mongoose mongodb-query


【解决方案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 } },
])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-23
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    • 2015-02-01
    • 2019-02-12
    相关资源
    最近更新 更多