You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:07:29