请问如何在使用Nodejs时保持不同地方的数据库查询代码DRY?

请问如何在使用Nodejs时保持不同地方的数据库查询代码DRY?

我使用mongoose,在很多不同的routes里面,都需要查询一个collection,比如Topics。
查询的条件都各有不同,比如{user_id:xxx},比如{tag:xxx},也有用where来查询的,比如 Topics.find().where(user).in([xx])。

但是这些查询之后的modifier都是一样的,比如.populate,.sort,.limit之类的,里面的参数都相同。那请问有没有什么办法能把这些modifier放在一个地方?

2 回复

当然可以!在Node.js中使用Mongoose时,可以通过创建一个通用的查询函数来避免重复代码(DRY原则)。以下是一个示例,展示了如何实现这一点。

示例代码

首先,我们定义一个通用的查询函数,该函数接受查询条件、修饰符和其他参数作为输入,并返回查询结果。

const mongoose = require('mongoose');
const Topic = mongoose.model('Topic');

// 定义一个通用的查询函数
async function findTopics(query, modifiers) {
    let queryResult;

    // 执行基础查询
    queryResult = await Topic.find(query);

    // 应用修饰符
    if (modifiers.sort) {
        queryResult = queryResult.sort(modifiers.sort);
    }
    if (modifiers.limit) {
        queryResult = queryResult.limit(modifiers.limit);
    }
    if (modifiers.populate) {
        queryResult = queryResult.populate(modifiers.populate);
    }

    return queryResult;
}

使用示例

接下来,我们可以在不同的路由中使用这个通用的查询函数:

const express = require('express');
const router = express.Router();

router.get('/topics-by-user', async (req, res) => {
    const user_id = req.query.user_id;
    const query = { user_id };
    const modifiers = {
        sort: { createdAt: -1 },
        limit: 10,
        populate: 'comments'
    };

    try {
        const topics = await findTopics(query, modifiers);
        res.json(topics);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

router.get('/topics-by-tag', async (req, res) => {
    const tag = req.query.tag;
    const query = { tag };
    const modifiers = {
        sort: { views: -1 },
        limit: 5,
        populate: 'author'
    };

    try {
        const topics = await findTopics(query, modifiers);
        res.json(topics);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

解释

  1. 通用查询函数

    • findTopics 函数接受两个参数:querymodifiers
    • query 是用于查询的条件对象。
    • modifiers 是一个对象,包含 .sort, .limit, .populate 等修饰符。
  2. 应用修饰符

    • findTopics 函数内部,我们检查每个修饰符是否被提供,并相应地应用它们。
  3. 路由示例

    • 我们在不同的路由中使用 findTopics 函数,传入相应的查询条件和修饰符。
    • 这样可以确保相同的逻辑不会在多个地方重复出现,从而提高代码的可维护性和可读性。

通过这种方式,我们可以有效地保持代码的 DRY 原则,同时确保代码的清晰和模块化。


为了保持不同地方的数据库查询代码 DRY(Don’t Repeat Yourself),可以将重复使用的 .populate.sort.limit 等操作封装成一个函数或方法,并通过传入不同的查询条件来实现复用。以下是一种可能的实现方式:

示例代码

首先,定义一个函数来封装这些重复的操作:

const mongoose = require('mongoose');
const Topic = mongoose.model('Topic', new mongoose.Schema({}));

function getTopics(query, populateFields, sortCriteria, limit) {
    return Topic.find(query)
        .populate(populateFields)
        .sort(sortCriteria)
        .limit(limit);
}

然后,在路由中调用这个函数:

const express = require('express');
const router = express.Router();
const { getTopics } = require('./utils/topics'); // 假设上面的函数定义在这个路径下

router.get('/topics/user/:userId', async (req, res) => {
    const topics = await getTopics(
        { user_id: req.params.userId },
        'author', // 要填充的字段名
        { createdAt: -1 }, // 排序方式
        10 // 限制条数
    );
    res.json(topics);
});

router.get('/topics/tag/:tag', async (req, res) => {
    const topics = await getTopics(
        { tag: req.params.tag },
        'author',
        { viewCount: -1 },
        5
    );
    res.json(topics);
});

解释

  • getTopics 函数接受四个参数:

    • query:MongoDB 查询对象。
    • populateFields:要填充的字段名称数组。
    • sortCriteria:排序条件对象。
    • limit:结果集数量限制。
  • 在每个路由处理函数中,我们只需要传递具体的查询条件给 getTopics 函数,这样就能避免重复编写相同的 .populate.sort.limit 操作。

这种方式不仅可以使代码更加整洁,还能方便地维护和更新查询逻辑。

回到顶部