在 go mongodb 中的 From Table 上匹配阶段

Posted

技术标签:

【中文标题】在 go mongodb 中的 From Table 上匹配阶段【英文标题】:Match Stage on From Table in go mongodb 【发布时间】:2020-11-30 18:50:34 【问题描述】:

我的 mongodb 集合

employee

  _id:ObjectId(),
  "emp_name":"qwert",
  "emp_id":111,
  "emp_dept":"XYZ"
  "qualification":"PHD"


_id:ObjectId(),
  "emp_name":"asdfg",
  "emp_id":121,
  "emp_dept":"XYZ"
 "qualification":"MBA"

department
_id:ObjectId(),
"dept_id":11,
"dept_name":"XYZ",
"description":"decs",

我的 Go 代码是

 type Employee struct 
    EmployeeName  string             `json:"emp_name" bson:"emp_name"`
    EmployeeID    int                `json:"emp_id" bson:"emp_id"`
    EmployeeDept  string             `json:"emp_dept" bson:"emp_dept"`
    EmpQualification string          `json:"qualification" bson:"quaification"` 
    EmpDepartment Department         `json:"department" bson:"department"` 

 type Department struct 
    DepartmentID    int                `json:"dept_id" bson:"dept_id"`
    DepartmentName  string             `json:"dept_name" bson:"dept_name"` 
    Description     string             `json:"description" bson:"description"` 
    EmployeeList    []Employee         `json:"employee_list" bson:"employee_list"`


collection := session.DB("db").C("department")
pipeline := collection.Pipe([]bson.M
        "$lookup": bson.M
        "from":         "employee",
        "localField":   "dept_name",
        "foreignField": "emp_dept",
        "as":           "employee_list",
    ,
      "$match": bson.M
        "qualification": "PHD",
          ,
    )

err = pipeline.All(&departmentEmployees)

显示空结果

我想从我的部门集合中获取所有部门,每个部门都有“PHD”资格的员工列表。我已将我的集合和结构上传为示例。如何在查找表中使用匹配字段。

我想得到类似的输出


    dept_id:11,
   dept_name:'XYZ'
   description:'desc'
   employee_list:[
     
     emp_name:"qwerty"
     emp_id:111,
     qualification:'PHD' 
     
     
     emp_name:"asdfg"
     emp_id:222,
     qualification:'PHD' 
     
...
]
 
    dept_id:12,
   dept_name:'ABC'
   description:'descwe'
   employee_list:[
     
     emp_name:"bjgk"
     emp_id:865,
     qualification:'PHD' 
     
     
     emp_name:"hkj"
     emp_id:967,
     qualification:'PHD' 
     
...
]

对于第一所大学,让所有员工获得博士学位,然后在第二所大学等等。我很困惑我是否必须在查找中使用 group by in from collection?

【问题讨论】:

【参考方案1】:

首先,您的 Employee.EmpQualification 字段标签中有错字:

EmpQualification string `json:"qualification" bson:"quaification"`

应该是:

EmpQualification string `json:"qualification" bson:"qualification"`

接下来,当您以employee_list 查找员工时,这将是结果中的一个新字段,因此qualification 将引用department 的字段,而不是员工的字段。

而且由于employee_list是一个数组,你不能简单地匹配,你必须过滤数组,并用新的过滤数组替换employee_list

最后,您可能希望排除没有任何具有“博士”资格的员工的部门。

最终的聚合如下所示:

pipeline := collection.Pipe([]bson.M
    "$lookup": bson.M
        "from":         "employee",
        "localField":   "dept_name",
        "foreignField": "emp_dept",
        "as":           "employee_list",
    ,
    
        "$addFields": bson.M
            "employee_list": bson.M
                "$filter": bson.M
                    "input": "$employee_list",
                    "as":    "emp",
                    "cond":  bson.M
                        "$eq": []interface"$$emp.qualification", "PHD",
                    ,
                ,
            ,
        ,
    ,
    "$match": bson.M
        "employee_list": bson.M"$not": bson.M"$size": 0,
    ,
)

还要注意,上述聚合必须搜索所有部门及其员工。更好的方法是从员工开始,按资格筛选,然后按部门分组。

扩展第二种方法:一旦你有拥有 PHD 的员工,按emp_dept 分组并将员工聚集在employee_list 中,然后查找部门。然后你必须“构造”结果文档,即查找的部门必须是“根”加上一个额外的emplyee_list(在$group阶段收集)。

这就是它的样子:

pipeline := collection.Pipe([]bson.M
    "$match": bson.M
        "qualification": "PHD",
    ,
    "$group": bson.M
        "_id":           "$emp_dept",
        "employee_list": bson.M"$push": "$$ROOT",
    ,
    "$lookup": bson.M
        "from":         "department",
        "localField":   "_id",
        "foreignField": "dept_name",
        "as":           "department",
    ,
    "$unwind": "$department",
    "$replaceRoot": bson.M
        "newRoot": bson.M
            "$mergeObjects": []interface
                "$department",
                bson.M"employee_list": "$employee_list",
            ,
        ,
    ,
)

第二种方法的优点是它只处理拥有 PHD 的员工(确保有一个索引),只加载拥有此类员工的部门。

另请注意,最好将部门 ID 存储在员工中而不是部门名称中,如果您将来必须重命名部门,您只需在一个位置(在部门文件)。

【讨论】:

非常感谢它对我有用。我有一个问题,我在匹配字段中有四个参数,所以我必须确保所有的索引吗? @RajandeepKaur 您应该只为您的查询创建索引。如果您从不按字段过滤/查询,则应该没有索引。 当我发送请求时,每次我的结果都会改变。它基于我的匹配参数,但结果顺序发生了变化,例如我第一次得到 dept_id=1 结果,然后第二次得到 dept_id=2 结果,这是什么原因? @RajandeepKaur 无序/无序查询不保证任何顺序。如果您需要订单,请明确对结果进行排序。 我想使用 $skip 和 $limit。所以我必须在 $unwind 之后或 $replaceRoot 之后写它

以上是关于在 go mongodb 中的 From Table 上匹配阶段的主要内容,如果未能解决你的问题,请参考以下文章

带有 mgo 的 Go (golang) 中的 MongoDB:如何更新记录、确定更新是不是成功并在单个原子操作中获取数据?

golang Go中的简单HTTP服务器使用mongoDB和通道

如何在 Go 中使用 .crt 文件通过 ssl 连接到 mongoDB

Mongodb 查询执行耗时过长

Go mgo 包中的连接池

为 MongoDB 上的 CRUD 操作组织 Go 代码