如何为mongoose创建多重过滤

kadbb459  于 11个月前  发布在  Go
关注(0)|答案(3)|浏览(148)

我有一个在线游戏商店和代码,可以通过标签和流派过滤数据。但我还想添加平台和系统过滤。例如,系统是PC,平台是Steam。我如何实现这一点?

架构

const mongoose = require("mongoose");
const slug = require('mongoose-slug-updater');
const options = {
    separator: "-",
    lang: "en",
    truncate: 120
}
mongoose.plugin(slug, options);
const GamesSchema = new mongoose.Schema({
    title: String,
    slug: { type: String, slug: ["title"], slugPaddingSize: 2, unique: true },
    last_url: String,
    description: String,
    preview: {
        src: String,
        alt: String
    },
    stock_price: String,
    discount: Number,
    total_price: String,
    system: Array,
    platform: String,
    info: {
        Genre: Array
    },
    tags: Array,
    config: Object,
    images: Array,
    keys: Array,
    content: String
})
module.exports = mongoose.model("Games", GamesSchema);

字符串

API控制器

async get(req, res) {
        try {
            const page = parseInt(req.query.page) - 1 || 0;
            const limit = parseInt(req.query.limit) || 5;
            const search = req.query.search || '';
            let sort = req.query.sort || "top";
            let tags = req.query.tags || 'all';
            const tagsOpt = [];
            Games.find().then(async games => {
                games.forEach(game => {
                    game.tags.forEach(tag => {
                        if (!tagsOpt.includes(tag)) {
                            tagsOpt.push(tag)
                        }
                    })
                })

                tags === 'all' ? (tags = [...tagsOpt]) : (tags = req.query.tags.split(','));
                req.query.sort ? (sort = req.query.sort.split(',')) : (sort = [sort]);

                let sortBy = {};
                if (sort[1]) {
                    sortBy[sort[0] = sort[1]];
                } else {
                    sortBy[sort[0] = "top"]
                }
                const gamesData = await Games.find({ title: { $regex: search, $options: 'i' } })
                    .where('tags')
                    .in([...tags])
                    .sort(sortBy)
                    .skip(page * limit)
                    .limit(limit);

                const total = await Games.countDocuments({
                    tags: { $in: [...tags] },
                    title: { $regex: search, $options: 'i' },
                });
                const response = {
                    error: false,
                    total,
                    page: page + 1,
                    limit,
                    tags: tagsOpt,
                    gamesData
                };
                res.status(200).json(response);
            })
        } catch (error) {
            console.log(error);
            res.status(400).json({ message: 'Ошибка получения' })
        }
    }


我能够将合并类型和标签组合成一个并通过它们进行过滤,我现在真的需要将平台和系统都放入一个标签数组中吗?

13z8s7eq

13z8s7eq1#

不需要,您不需要将平台和系统都放入标签数组中。您可以分别按平台和系统进行筛选。
您可以在API中为平台和系统添加两个查询参数,然后在mongoose查询中使用它们。具体操作如下:

async get(req, res) {
    try {
        const page = parseInt(req.query.page) - 1 || 0;
        const limit = parseInt(req.query.limit) || 5;
        const search = req.query.search || '';
        let sort = req.query.sort || "top";
        let tags = req.query.tags || 'all';
        const platform = req.query.platform || '';
        const system = req.query.system || '';
        const tagsOpt = [];
        Games.find().then(async games => {
            games.forEach(game => {
                game.tags.forEach(tag => {
                    if (!tagsOpt.includes(tag)) {
                        tagsOpt.push(tag)
                    }
                })
            })

            tags === 'all' ? (tags = [...tagsOpt]) : (tags = req.query.tags.split(','));
            req.query.sort ? (sort = req.query.sort.split(',')) : (sort = [sort]);

            let sortBy = {};
            if (sort[1]) {
                sortBy[sort[0] = sort[1]];
            } else {
                sortBy[sort[0] = "top"]
            }
            const gamesData = await Games.find({ 
                title: { $regex: search, $options: 'i' },
                platform: { $regex: platform, $options: 'i' },
                system: { $in: system.split(',') }
            })
                .where('tags')
                .in([...tags])
                .sort(sortBy)
                .skip(page * limit)
                .limit(limit);

            const total = await Games.countDocuments({
                tags: { $in: [...tags] },
                title: { $regex: search, $options: 'i' },
                platform: { $regex: platform, $options: 'i' },
                system: { $in: system.split(',') }
            });
            const response = {
                error: false,
                total,
                page: page + 1,
                limit,
                tags: tagsOpt,
                gamesData
            };
            res.status(200).json(response);
        })
    } catch (error) {
        console.log(error);
        res.status(400).json({ message: 'Ошибка получения' })
    }
}

字符串
在这段代码中,我添加了两个新的查询参数platform和system。platform是一个字符串,system是一个数组。我为platform使用了$regex,使其不区分大小写,为system使用了$in,以匹配数组中的任何系统。
现在,您可以通过在API请求中添加平台和系统参数来按平台和系统过滤游戏,如下所示:/API/games?platform=Steam&system=PC,Mac。
请将文件路径替换为实际文件路径。

cngwdvgl

cngwdvgl2#

谢谢你,谢谢)这个解决方案是有效的,但我做得有点不同,因为我需要按平台和系统进行多搜索,也就是说,我可以同时过滤PC,Xbox以及Steam Origin平台等。

const page = parseInt(req.query.page) - 1 || 0;
        const limit = parseInt(req.query.limit) || 5;
        const search = req.query.search || '';
        let sort = req.query.sort || "rating";
        let tags = req.query.tags || 'all';
        let system = req.query.system || 'all';
        let platform = req.query.platform || 'all';
        let language = req.query.language || 'all';
        const tagsOpt = [];
        const platformOpt = [];
        const systemOpt = [];
        const languageOpt = [];
        Games.find().then(async games => {
            games.forEach(game => {
                game.tags.forEach(tag => {
                    if (!tagsOpt.includes(tag)) {
                        tagsOpt.push(tag)
                    }
                })
                if (!platformOpt.includes(game.platform)) {
                    platformOpt.push(game.platform)
                }
                if (!systemOpt.includes(game.system)) {
                    systemOpt.push(game.system)
                }
                game.languages.forEach(language => {
                    if (!languageOpt.includes(language)) {
                        languageOpt.push(language)
                    }
                })
            })

            tags === 'all' ? (tags = [...tagsOpt]) : (tags = req.query.tags.split(','));
            platform === 'all' ? (platform = [...platformOpt]) : (platform = req.query.platform.split(','));
            system === 'all' ? (system = [...systemOpt]) : (system = req.query.system.split(','));
            language === 'all' ? (language = [...languageOpt]) : (language = req.query.language.split(','));
            req.query.sort ? (sort = req.query.sort.split(',')) : (sort = [sort]);

            let sortBy = {};
            if (sort[1]) {
                sortBy[sort[0]] = sort[1];
            } else {
                sortBy[sort[0]] = "asc";
            }
            const gamesData = await Games.find({ title: { $regex: search, $options: 'i' } })
                .where('tags').in([...tags])
                .where('platform').in([...platform])
                .where('system').in([...system])
                .where('languages').in([...language])
                .sort(sortBy)
                .skip(page * limit)
                .limit(limit);

            const total = await Games.countDocuments({
                tags: { $in: [...tags] },
                title: { $regex: search, $options: 'i' },
            });
            const response = {
                error: false,
                total,
                page: page + 1,
                limit,
                tags: tagsOpt,
                language: languageOpt,
                platform: platformOpt,
                system: systemOpt,
                gamesData
            };
            res.status(200).json(response);
        })

字符串
我可以优化它吗?

cetgtptt

cetgtptt3#

你的代码执行了很多可以优化的操作。下面是一些建议:
使用MongoDB的聚合框架:聚合框架是一个强大的工具,允许您直接在数据库中对数据执行复杂的转换和计算。这比检索数据并在应用程序中处理它要快得多。避免不必要的数据库调用:您的代码当前调用了Games.find()两次,一次是获取标签、平台、系统和语言的选项,一次用于获取实际的游戏数据。您可以使用聚合框架将其减少为单个调用。使用投影来限制数据库返回的字段:如果您只需要文档中的某些字段,可以使用投影来限制返回的字段。这可以减少需要从数据库传输到应用程序,可以提高性能。
下面是一个如何实现这些建议的示例:

const page = parseInt(req.query.page) - 1 || 0;
const limit = parseInt(req.query.limit) || 5;
const search = req.query.search || '';
let sort = req.query.sort || "rating";
let tags = req.query.tags || 'all';
let system = req.query.system || 'all';
let platform = req.query.platform || 'all';
let language = req.query.language || 'all';

tags = tags === 'all' ? [] : tags.split(',');
platform = platform === 'all' ? [] : platform.split(',');
system = system === 'all' ? [] : system.split(',');
language = language === 'all' ? [] : language.split(',');
platform = platform === 'all' ? [] : platform.split(',');
system = system === 'all' ? [] : system.split(',');

sort = sort.split(',');
let sortBy = {};
if (sort[1]) {
    sortBy[sort[0]] = sort[1];
} else {
    sortBy[sort[0]] = "asc";
}

const pipeline = [
    { $match: { title: { $regex: search, $options: 'i' } } },
    { $match: { platform: { $in: platform } } },
    { $match: { system: { $in: system } } },
    { $match: { tags: { $in: tags } } },
    { $match: { platform: { $in: platform } } },
    { $match: { system: { $in: system } } },
    { $match: { languages: { $in: language } } },
    { $sort: sortBy },
    { $skip: page * limit },
    { $limit: limit },
    { $project: { /* specify the fields you need here */ } }
];

const gamesData = await Games.aggregate(pipeline).exec();

const total = await Games.countDocuments({
    tags: { $in: tags },
    title: { $regex: search, $options: 'i' },
});

const response = {
    error: false,
    total,
    page: page + 1,
    limit,
    gamesData
};

res.status(200).json(response);

字符串
这段代码使用aggregation框架直接在数据库中执行所有的过滤、排序和分页。它还使用投影来限制返回的字段,尽管你需要在$project阶段填写你需要的字段。
请注意,此代码假设如果为标签、平台、系统或语言传递了“all”,则意味着该字段可以接受任何值。如果“all”应被视为特定值,则需要相应地调整代码。
此外,这段代码没有在响应中包含标签,平台,系统和语言的选项。如果你仍然需要这些选项,你可以考虑缓存它们,以避免每次都需要计算它们。

相关问题