Mongoose find查询中使用文档属性值访问另一集合对应属性的实现方案
问题根因
你原有代码的错误点在于:settings.maxAnnotations["$language"] 是在Node.js服务端代码中执行的取值操作,并非MongoDB查询引擎内部的表达式计算,因此$language不会被替换为Letter文档对应的language字段值,只是被当成普通字符串去settings对象中找不存在的$language属性,自然无法得到预期结果。
推荐解决方案
因为你已经提前查询到了全局的settings配置,且allowedLanguages是可枚举的固定数组,直接构造分语言的$or查询条件即可,该方案兼容性好、查询性能高,可正常使用索引:
const Letters = require("../models/letters"); // 注意你原来的拼写错误:lettters -> letters const Settings = require("../models/settings"); exports.getLetters = async (req, res, next) => { // 注意你原来的代码漏了req前缀 const pageSize = +req.query.pagesize; const currentPage = +req.query.currentPage; const allowedLanguages = ["english", "french"]; const settings = await Settings.findOne(); const toAllLanguages = settings.maxAnnotations.toAllLanguages.enabled; let letters; if (toAllLanguages) { letters = await Letters.find({ language: { $in: allowedLanguages }, annotations: { $lt: settings.maxAnnotations.toAllLanguages.amount } }) .skip(pageSize * (currentPage - 1)) .limit(pageSize); } else { // 构造各语言对应的阈值条件 const langConditions = allowedLanguages.map(lang => ({ language: lang, annotations: { $lt: settings.maxAnnotations[lang] } })); letters = await Letters.find({ $or: langConditions }) .skip(pageSize * (currentPage - 1)) .limit(pageSize); } // 补充你原来缺失的返回逻辑 res.status(200).json(letters); };
可选方案(仅MongoDB 5.0+支持)
如果你使用的MongoDB版本≥5.0,也可以用$getField操作符在查询表达式中动态取对应语言的阈值,代码如下:
else { const letters = await Letters.find({ language: { $in: allowedLanguages }, $expr: { $lt: [ "$annotations", { $getField: { field: "$language", input: settings.maxAnnotations } } ] } }) .skip(pageSize * (currentPage - 1)) .limit(pageSize); }
该方案无需循环构造条件,但是性能略低于第一种方案,且存在版本要求,更推荐使用第一种方案。
内容的提问来源于stack exchange,提问作者Rafael Guerra
相关产品推荐
相关产品推荐

