如何在MongoDB中获取users数组指定元素的索引(替代服务器端处理)
问题背景
我有如下MongoDB Schema:
const universitiesSchema = new Schema({ name: { type: String, required: [true, 'Required'] }, users: { type:[Schema.Types.ObjectId], } });
需要根据特定user_id获取其在users数组中的索引。当前实现是将整个文档拉取到Web服务器后,用indexOf计算索引:
const unis = await Universities.findOne({ _id: university_id }); const userIndex = unis.users.indexOf(new mongoose.Types.ObjectId(user_id));
但users数组未来会非常庞大,希望直接由MongoDB完成索引计算,避免在服务器端处理大量数据。
解决方案
方法1:使用$indexOfArray(MongoDB 4.4+ 推荐)
MongoDB 4.4及以上版本支持$indexOfArray操作符,可直接在数据库端返回元素在数组中的索引(元素不存在时返回-1)。对应的Mongoose代码如下:
const result = await Universities.aggregate([ { $match: { _id: new mongoose.Types.ObjectId(university_id) } }, { $project: { userIndex: { $indexOfArray: ['$users', new mongoose.Types.ObjectId(user_id)] } } } ]); const userIndex = result.length ? result[0].userIndex : -1;
该方法只需返回计算后的索引值,无需传输整个庞大的users数组,性能更优。
方法2:兼容旧版本MongoDB(4.4以下)
若使用低于4.4的MongoDB版本,可通过$unwind配合$group模拟索引计算:
const result = await Universities.aggregate([ // 先过滤包含目标user_id的文档,减少后续计算量 { $match: { _id: new mongoose.Types.ObjectId(university_id), users: new mongoose.Types.ObjectId(user_id) } }, // 展开数组并保留元素索引 { $unwind: { path: '$users', includeArrayIndex: 'userIndex' } }, // 匹配目标user_id对应的元素 { $match: { users: new mongoose.Types.ObjectId(user_id) } }, // 聚合取出索引值 { $group: { _id: '$_id', userIndex: { $first: '$userIndex' } } } ]); const userIndex = result.length ? result[0].userIndex : -1;
这种方法会先过滤掉不包含目标user_id的文档,再展开数组计算索引,相比拉取整个数组到服务器仍更高效。
内容的提问来源于stack exchange,提问作者spongebob89
相关产品推荐
相关产品推荐

