Rajesh Kumar
Rajesh Kumar

Reputation: 207

to find the last index of the array in mongodb

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

 type (
        Employee struct {
            Name               string
            Password           string
            EmpId              string 
           EmailAddress       string
           Position           string
           Gender             string
           Nationality        string
           Department         string
           MaritalStatus      string
           Approvedby         string
           JoinDate           time.Time
           ConfirmationDate   time.Time
           EndDate            time.Time
            Leave             []*LeaveInfo  
        }
        LeaveInfo struct {
            Total        float64
            Id           int
            Days         float64
            From        time.Time
             To          time.Time  
            Status       string
            Certificate  []*CertificateInfo
        }
        CertificateInfo struct {
            FileName string
            FileType string
            FileSize int

        }

Here is how i do in my application

 My code is follows

    employee := Employee{}
    err = c.Find(bson.M{
                  "empid": "1234"
                 }).One(&result)
    if err != nil {
            log.Fatal(err)
    }
          name:=result.Name        
          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

 This code is based on your example

   var result bson.M

    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,{
    "$project":bson.M{
           "ID":bson.M{
                "$slice": []interface{}{"$leave.id", -1},
        }
       }


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

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

Upvotes: 1

Views: 680

Answers (1)

dgm
dgm

Reputation: 123

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.

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.

Upvotes: 1

Related Questions