MongoDB聚合查询:如何对对象数组类型的结果进行切片?解决$slice参数类型错误问题
解决MongoDB聚合中$slice的类型错误问题
首先得说清楚你为啥踩这个坑:你用$slice的思路完全错了。$slice是专门用来处理数组字段的,但你在page_limit_stage里把$$CURRENT(或者后来改成的$CURRENT)传给它——这玩意儿是管道里的单个文档对象,不是数组,MongoDB自然会报错说“First argument to $slice must be an array, but is of type: object”。
你的需求是对聚合结果做分页,对吧?那根本不需要用$slice,MongoDB聚合自带$skip和$limit阶段干这个,这俩是作用在整个文档流上的,专门用来实现分页逻辑。
正确的修改方案
删掉你原来的page_limit_stage,换成$skip和$limit两个阶段,放到管道的最后就行:
const filterProfiles = async function filterProfiles() { const { users_filter_option, profiles_filter_option } = prepareProfilesFilterSearchOptions(); const profile_stage = { $lookup: { from: "profiles", let: { profile_id: "$profile" }, pipeline: [profiles_filter_option], as: "profile", }, }; const profile_populate_options = [ { $lookup: { from: "schema_name_1", localField: "profile.schema_name_1", foreignField: "_id", as: "schema_name_1", }, }, { $lookup: { from: "schema_name_2", localField: "profile.schema_name_2", foreignField: "_id", as: "schema_name_2", }, }, ]; const project_stage = { $project: { user_id: "$_id", name: "$name", surname: "$surname", country: "$country", schema_name_2: { $arrayElemAt: ["$schema_name_2", 0] }, schema_name_1: "$schema_name_1", }, }; let limit = 5; let skip = limit * 1; // 这里对应第2页,第1页的话skip应该设为0 // 替换原page_limit_stage为$skip和$limit阶段 const pipeline = [ users_filter_option, profile_stage, ...profile_populate_options, { $unwind: "$profile" }, project_stage, { $skip: skip }, // 跳过指定数量的前置文档 { $limit: limit } // 限制返回的文档数量 ]; const users = await User.aggregate(pipeline); return users; };
为啥原来的方法行不通?
再给你理清楚逻辑:
$project阶段是针对单个文档做字段投影的,它处理的是单个对象,不是整个结果数组。$slice的正确用法是处理文档内的数组字段,比如你有一个tags数组,想取前3个元素,写法是tags: { $slice: ["$tags", 3] },这才是合规的。- 而对整个聚合结果做分页,必须用
$skip+$limit:$skip先跳过指定数量的文档,$limit再限制返回条数,这是MongoDB聚合实现分页的标准方式。
这样修改后,你就能得到正确的分页结果,再也不会碰到那个类型错误了。
内容的提问来源于stack exchange,提问作者AG_HIHI
相关产品推荐
相关产品推荐

