请问如何在使用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放在一个地方?
当然可以!在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 });
}
});
解释
-
通用查询函数:
findTopics
函数接受两个参数:query
和modifiers
。query
是用于查询的条件对象。modifiers
是一个对象,包含.sort
,.limit
,.populate
等修饰符。
-
应用修饰符:
- 在
findTopics
函数内部,我们检查每个修饰符是否被提供,并相应地应用它们。
- 在
-
路由示例:
- 我们在不同的路由中使用
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
操作。
这种方式不仅可以使代码更加整洁,还能方便地维护和更新查询逻辑。