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

Mongoid查询:获取缺少至少一类必填文档的用户

问题分析与解决方案

你的代码存在两个核心问题,导致查询结果不符合预期:

  1. 错误的筛选条件:$or数组中的第二个条件{ "$and" => required_categories.map { |cat| { :"documents.category" => cat } } }是在筛选拥有所有必填分类文档的用户,这和你的需求完全相反,必须移除。
  2. 无文档用户的判断逻辑错误:因为你用的是User has_many Document的引用关联(而非嵌入关联),User集合的文档中并不存在documents字段,所以原代码中通过$size判断数组长度的方式根本无法定位到无文档的用户。

下面提供两种可行的修正方案:

方案一:分查询合并(简洁易读)

def self.without_all_required_documents
  required_cats = required_categories

  # 1. 找出有文档但缺少至少一个必填分类的用户ID
  missing_required_user_ids = Document.collection.aggregate([
    { "$match" => { "user_id" => { "$ne" => nil }, "category" => { "$in" => required_cats } } },
    { "$group" => { "_id" => "$user_id", "existing_categories" => { "$addToSet" => "$category" } } },
    # 直接比较现有必填分类数量和总必填数量,判断是否缺失
    { "$match" => { "$expr" => { "$lt" => [ { "$size" => "$existing_categories" }, required_cats.size ] } } },
    { "$project" => { "_id" => 1 } }
  ]).pluck("_id")

  # 2. 找出完全没有任何文档的用户(排除所有有文档的用户ID)
  no_documents_condition = { id: { "$nin" => Document.distinct(:user_id) } }

  # 合并两个条件
  where(:"$or" => [
    { id: { "$in" => missing_required_user_ids } },
    no_documents_condition
  ])
end

方案二:单聚合查询(性能更优)

通过MongoDB的$lookup关联用户与文档,一次性完成筛选,减少数据库交互次数:

def self.without_all_required_documents
  required_cats = required_categories

  target_user_ids = collection.aggregate([
    # 关联用户的所有文档
    {
      "$lookup" => {
        from: "documents",
        localField: "_id",
        foreignField: "user_id",
        as: "user_documents"
      }
    },
    # 计算关键指标:是否有文档、已拥有的必填分类集合
    {
      "$project" => {
        "_id" => 1,
        "has_documents" => { "$gt" => [ { "$size" => "$user_documents" }, 0 ] },
        "existing_required_cats" => {
          "$setIntersection" => [
            required_cats,
            { "$map" => { input: "$user_documents", as: "doc", in: "$$doc.category" } }
          ]
        }
      }
    },
    # 筛选目标用户:无文档 或 缺少必填分类
    {
      "$match" => {
        "$or" => [
          { "has_documents" => false },
          { "$expr" => { "$lt" => [ { "$size" => "$existing_required_cats" }, required_cats.size ] } }
        ]
      }
    },
    { "$project" => { "_id" => 1 } }
  ]).pluck("_id")

  where(id: target_user_ids)
end

说明

  • 两种方案都能准确筛选出两类目标用户:完全无文档的用户、有文档但缺少至少一个必填分类的用户。
  • 方案一逻辑拆分清晰,适合调试;方案二用单次聚合完成,性能更优,适合数据量较大的场景。

内容的提问来源于stack exchange,提问作者Samy Kacimi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 16:52:11