MongoDB聚合查询求助:添加排除条件并获取最新登录记录(CodeIgniter)
没问题,我来帮你搞定这两个需求!咱们一步步拆解来解决:
1. 在聚合查询中添加where_not_in对应的条件
你原来PHP代码里的where_not_in('type', array($instituteAdmin)),对应MongoDB聚合$match阶段的$nin(Not In)操作符。直接把这个条件合并到第一个$match管道阶段里就可以,不用单独加新的阶段。
原生MongoDB的聚合示例会变成这样:
db.user.aggregate([ { $match: { instituteId: '5954ee6dcf2169d50d51b88d', type: { $nin: [/* 这里传入你的$instituteAdmin变量值 */] } } }, { $lookup: { from: "user_login_details", localField: "_id", foreignField: "user_id", as: "user_login_details" } } ]).pretty()
2. 只获取user_login_details的最新记录
要只保留每个用户的最新登录记录,最高效的方式是在$lookup里使用子管道查询(MongoDB 3.6及以上版本支持)——这样不用拉取所有登录记录再过滤,直接在关联查询时就只返回最新的那一条。
假设你的user_login_details集合里有记录登录时间的字段(比如login_time,你可以换成实际字段名),子管道里先匹配对应用户,再按时间倒序排序,最后只取第一条:
原生MongoDB示例:
db.user.aggregate([ { $match: { instituteId: '5954ee6dcf2169d50d51b88d', type: { $nin: [/* $instituteAdmin的值 */] } } }, { $lookup: { from: "user_login_details", let: { userId: "$_id" }, // 定义变量传递user集合的_id pipeline: [ { $match: { $expr: { $eq: ["$user_id", "$$userId"] } } }, // 匹配对应用户 { $sort: { login_time: -1 } }, // 按登录时间倒序,最新的排在最前面 { $limit: 1 } // 只取第一条 ], as: "user_login_details" } }, // 可选操作:如果不想让user_login_details是数组,用$unwind展开成对象 { $unwind: { path: "$user_login_details", preserveNullAndEmptyArrays: true } } ]).pretty()
3. 用CodeIgniter MongoDB Active Record Library编写PHP代码
把上面的逻辑转化为CI的代码,注意替换实际的时间字段名和变量:
// 构建聚合管道数组 $pipeline = [ // 第一阶段:匹配用户条件(包含instituteId和type的排除规则) [ '$match' => [ 'instituteId' => $instituteId, 'type' => ['$nin' => [$instituteAdmin]] ] ], // 第二阶段:关联并获取最新登录记录 [ '$lookup' => [ 'from' => 'user_login_details', 'let' => ['userId' => '$_id'], 'pipeline' => [ ['$match' => ['$expr' => ['$eq' => ['$user_id', '$$userId']]]], ['$sort' => ['login_time' => -1]], // 替换成你实际的时间字段名 ['$limit' => 1] ], 'as' => 'user_login_details' ] ], // 可选:展开登录记录数组,让它变成单个对象(如果不需要数组形式的话) [ '$unwind' => [ 'path' => '$user_login_details', 'preserveNullAndEmptyArrays' => true // 即使没有登录记录,也保留用户数据 ] ] ]; // 执行聚合查询 $data = $this->mongodb->aggregate('user', $pipeline);
兼容旧版MongoDB的备选方案
如果你的MongoDB版本低于3.6,不支持$lookup的子管道,可以用下面的方式:先关联所有登录记录,再展开、排序、分组取最新一条。这种方法需要手动指定要保留的用户字段,效率稍低:
$pipeline = [ ['$match' => ['instituteId' => $instituteId, 'type' => ['$nin' => [$instituteAdmin]]]], ['$lookup' => ['from' => 'user_login_details', 'localField' => '_id', 'foreignField' => 'user_id', 'as' => 'user_login_details']], ['$unwind' => ['path' => '$user_login_details', 'preserveNullAndEmptyArrays' => true]], ['$sort' => ['_id' => 1, 'user_login_details.login_time' => -1]], ['$group' => [ '_id' => '$_id', 'instituteId' => ['$first' => '$instituteId'], 'type' => ['$first' => '$type'], // 这里要把user集合里需要保留的其他字段都用$first取出来 'user_login_details' => ['$first' => '$user_login_details'] ]] ]; $data = $this->mongodb->aggregate('user', $pipeline);
内容的提问来源于stack exchange,提问作者Amrish Khatri
相关产品推荐
相关产品推荐

