to find the last index of the array in mongodb

huangapple go评论115阅读模式
英文:

to find the last index of the array in mongodb

问题

在后端,我使用Go语言,数据库使用MongoDB。我正在尝试找到嵌套数组中最后插入的文档,以便我可以在不知道其索引的情况下检索最后一个数组索引中的文档。目前,我正在获取所有员工的文档,然后找到最后一个索引。这样做会导致我的RAM超载,因为我需要在找到数组的最后一个索引之前检索1000条员工记录并将其存储在RAM中。

我的结构如下:

  1. type (
  2. Employee struct {
  3. Name string
  4. Password string
  5. EmpId string
  6. EmailAddress string
  7. Position string
  8. Gender string
  9. Nationality string
  10. Department string
  11. MaritalStatus string
  12. Approvedby string
  13. JoinDate time.Time
  14. ConfirmationDate time.Time
  15. EndDate time.Time
  16. Leave []*LeaveInfo
  17. }
  18. LeaveInfo struct {
  19. Total float64
  20. Id int
  21. Days float64
  22. From time.Time
  23. To time.Time
  24. Status string
  25. Certificate []*CertificateInfo
  26. }
  27. CertificateInfo struct {
  28. FileName string
  29. FileType string
  30. FileSize int
  31. }
  32. )

以下是我在应用程序中的代码:

  1. employee := Employee{}
  2. err = c.Find(bson.M{
  3. "empid": "1234",
  4. }).One(&result)
  5. if err != nil {
  6. log.Fatal(err)
  7. }
  8. name := result.Name
  9. lastindex := result.LeaveInfo[len(result.LeaveInfo)-1].Id

正如你所看到的,我检索了整个员工数据,然后找到了最后一个文档的ID。有没有更好的方法来做到这一点?感谢任何帮助。谢谢。

新添加的代码

这段代码是基于你的示例:

  1. var result bson.M
  2. query := bson.M{"empid": "1234"} // 获取你感兴趣的员工
  3. match := bson.M{"$match": query} // 设置管道的匹配部分
  4. unwind := bson.M{"$unwind": "$leave"} // 设置要展开的leave字段
  5. pipeline := []bson.M{match, unwind, {
  6. "$project": bson.M{
  7. "ID": bson.M{
  8. "$slice": []interface{}{"$leave.id", -1},
  9. },
  10. },
  11. }}
  12. iter := postCollection.Pipe(pipeline).Iter()
  13. for iter.Next(&result) {
  14. fmt.Printf("%+v\n", result)
  15. }
  16. iter.Close()

这段代码给我返回了很多相同的文档,例如542个文档,但所有这些文档都是相同的。

英文:

In the back end i m using go lang and for database i use mongoDB. I m trying to find the last document inserted in the embedded array so i can retrieve the document in the last array index without knowing its index.Right now i m getting all the documents of the employee and then find the last index.It is like overloading my RAM as i need to retrieve 1000 of record of employee and store it in ram before finding the last index of the array
My struct is as follows

  1. type (
  2. Employee struct {
  3. Name string
  4. Password string
  5. EmpId string
  6. EmailAddress string
  7. Position string
  8. Gender string
  9. Nationality string
  10. Department string
  11. MaritalStatus string
  12. Approvedby string
  13. JoinDate time.Time
  14. ConfirmationDate time.Time
  15. EndDate time.Time
  16. Leave []*LeaveInfo
  17. }
  18. LeaveInfo struct {
  19. Total float64
  20. Id int
  21. Days float64
  22. From time.Time
  23. To time.Time
  24. Status string
  25. Certificate []*CertificateInfo
  26. }
  27. CertificateInfo struct {
  28. FileName string
  29. FileType string
  30. FileSize int
  31. }

Here is how i do in my application

  1. My code is follows
  2. employee := Employee{}
  3. err = c.Find(bson.M{
  4. "empid": "1234"
  5. }).One(&result)
  6. if err != nil {
  7. log.Fatal(err)
  8. }
  9. name:=result.Name
  10. lastindex:= result.LeaveInfo[len(result.LeaveInfo)-1].Id

As you can see i retrive the whole employee data and then find the Id of the last document.Is there any better way to do this.Appreciate any help.Please ...Thanks..

> Newly Added Codes

  1. This code is based on your example
  2. var result bson.M
  3. query := bson.M{"empid": "1234"} // gets the employee you are interested in
  4. match := bson.M{"$match": query} // Set up the match part of the pipeline
  5. unwind := bson.M{"$unwind": "$leave"} // sets up the leave field to be unwound
  6. pipeline := []bson.M{match, unwind,{
  7. "$project":bson.M{
  8. "ID":bson.M{
  9. "$slice": []interface{}{"$leave.id", -1},
  10. }
  11. }
  12. iter := postCollection.Pipe(pipeline).Iter()
  13. for iter.Next(&result) {
  14. fmt.Printf("%+v\n", result)
  15. }
  16. iter.Close()

This code gives me lot of same document like 542 documents .But all these document are same...

答案1

得分: 1

如果你正在运行一个具有 $slice 功能的Mongo版本,它是在2.4版本中引入的,你可以在Find中使用它,并添加一个Select函数,它的工作方式类似于project。

  1. err = c.Find(bson.M{"empid": "1234"}).Select(bson.M{"name": 1, "leave": bson.M{"$slice": -1}}).One(&result) // result是一个Employee结构体

否则,聚合是你的朋友。你需要使用一个管道并展开Employee的Leave字段。

以下是几个简单的步骤:

1)根据你的Employee记录定义一个结果记录,其中Leave字段被定义为单个LeaveInfo而不是LeaveInfos的切片,例如:

  1. type EmployeeResult struct {
  2. Name string `bson:"name"`
  3. Leave LeaveInfo `bson:"leave"`
  4. }

不要忘记将bson标签的名称与Employee结构体中LeaveInfo标签的名称相同。

2)然后创建一个包含几个阶段的管道:

  1. query := bson.M{"empid": "1234"} // 获取你感兴趣的员工
  2. match := bson.M{"$match": query} // 设置管道的匹配部分
  3. unwind := bson.M{"$unwind": "$leave"} // 设置要展开的leave字段
  4. pipeline := []bson.M{match, unwind} // 你传递给pipe的管道。我喜欢将pipe调用的各个部分分开,以提高清晰度和后续修改的便利性。

3)使用管道作为参数调用Pipe,然后迭代结果,这样你就可以一次获取一个LeaveInfo。

  1. var result EmployeeResult
  2. iter := postCollection.Pipe(pipeline).Iter()
  3. for iter.Next(&result) {
  4. fmt.Printf("%+v\n", result)
  5. }
  6. iter.Close()

4)在循环结束时,result将包含列表中的最后一个项目,如果没有读取到任何内容,则为空。

英文:

If you are running a version on Mongo which has $slice in it, It was introduced in 2.4, you can use it in a Find with the addition of a Select Function, which works like project.

  1. err = c.Find(bson.M{"empid": "1234"}).Select(bson.M{"name": 1, "leave": bson.M{"$slice": -1}}).One(&result) // result is an Employee struct

Otherwise, aggregation is your friend. You need to use a pipeline and unwind the Employee Leave field.

There are a few simple steps:

  1. Define a result record based on your Employee record where the Leave field is defined as a single LeaveInfo rather than a slice of LeaveInfos, eg

    EmployeeResult struct {
    Name string bson:"name"
    Leave LeaveInfo bson:"leave"
    }
    Do not forget to make the bson tag the same name as the LeaveInfo tag in the Employee struct.

  2. Then create a pipeline with a couple of stages:

    query := bson.M{"empid": "1234"} // gets the employee you are interested in
    match := bson.M{"$match": query} // Set up the match part of the pipeline
    unwind := bson.M{"$unwind": "$leave"} // sets up the leave field to be unwound
    pipeline := []bson.M{match, unwind} // the pipeline you are passing to pipe. I like to split the parts of the pipe call up for clarity and ease of later modification

  3. Call Pipe with the pipeline as a parameter then Iter over the results, this should give you one LeaveInfo at a time

    var (
    result EmployeeResult
    )
    iter := postCollection.Pipe(pipeline).Iter()
    for iter.Next(&result) {
    fmt.Printf("%+v\n", result)
    }
    iter.Close()

  4. At the end of the loop, result will have the last item in the list, or be blank if nothing was read.

huangapple
  • 本文由 发表于 2016年11月11日 17:19:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/40544700.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定