2

I have this function which uses the official mongo-go-driver (https://github.com/mongodb/mongo-go-driver)

func FindItemMongo(dataStruct interface{}, subItemKey string, collectionName string)(){
    fmt.Println("inside FindDataMongo in Controller")
    localDB := DB
    coll := localDB.Collection(collectionName)
    ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
    var searchData []uint8
    if subItemKey==""{
        fmt.Println("inside no key searchData")
        searchData, _ = bson.Marshal(bson.M{"data": dataStruct})
        fmt.Println("value of searchData")
        fmt.Println(searchData)
        fmt.Println("value of reflect type of searchData")
        fmt.Println(reflect.TypeOf(searchData))
    }else{
        reflectItem := reflect.ValueOf(dataStruct)
        subItem := reflectItem.FieldByName(subItemKey)
        subItemString := subItem.Interface().(string)
        searchData, _ =  bson.Marshal(bson.M{"data": bson.M{strings.ToLower(subItemKey): bson.M{"$eq": subItemString}}})
        fmt.Println("value of searchData")
        fmt.Println(searchData)
        fmt.Println("value of reflect type of searchData")
        fmt.Println(reflect.TypeOf(searchData))
    }
    cursor, err := coll.Find(ctx, searchData)
    if err != nil {
        log.Fatal(err)
    }
    defer cursor.Close(ctx)
    var returnBson []map[string]interface{}
    var result bson.M
    for cursor.Next(ctx) {
        err := cursor.Decode(&result)
        if err != nil { log.Fatal(err) }
        fmt.Println("value of found parsed")
        fmt.Println(result)
        returnBson = append(returnBson, result)
    }
}

Which is attempting to find data that is in the database for two conditions, related to the if statement. If the subItemKey is not defined, then it searches for an exact match to the passed in struct, if the key is defined, then it searches for a match in the data using the $eq operator for only a specific field.

This works for the condition where the subItemKey is empty. Like this:

database.FindItemMongo(dataStruct, "", "users")

Gives

api       | 1:36:55 app         | value of found parsed
api       | map[_id:ObjectID("8494398fsfd") data:map[email:qwer password:wer token:...]]

However, if I use the command:

database.FindItemMongo(dataStruct, "Email", "users")

I get nothing.

Something is not correct with how I define searchData in the else statement and I'm not sure what. Does anyone see what is going wrong?

EDIT

I should mention that the result of

    unmarshalledSearch := bson.M{"data": bson.M{strings.ToLower(subItemKey): bson.M{"$eq": subItemString}}}
    fmt.Println("value of unmarshalledSearch")
    fmt.Println(unmarshalledSearch)

is

api       | value of unmarshalledSearch
api       | map[data:map[email:map[$eq:qwer]]]

which is the same format as the data that is coming back from the empty field query. This is the crux of the problem - if the searchData appears to be correctly formatted, why is the cursor not returning with any results?

4
  • Your samples of FindItemMongo is the same above. What is the content of dataStruct? Commented Jan 31, 2019 at 4:04
  • type Login struct{ Email string json:"email"` Password string json:"password" Token string json:"token" } ` - What do you mean "...same as above"? Commented Jan 31, 2019 at 4:09
  • I mean the example for This works for the condition where the subItemKey is empty. Like this: and However, if I use the command: Commented Jan 31, 2019 at 4:44
  • Sorry! The empty one should not have the "Email" subItem. Commented Jan 31, 2019 at 5:00

3 Answers 3

2
+100

I'm new to Golang and do not have an environment to test this, but I think you should start by following the examples in the MongoDB Documentation and change

var searchData []uint8
    searchData, _ =  bson.Marshal(bson.M{"data": bson.M{strings.ToLower(subItemKey): bson.M{"$eq": subItemString}}})

to

var searchData bson.D
    searchData = bson.D{{"data." + strings.ToLower(subItemKey), bson.D{{"$eq", subItemString}}}}

You definitely should use bison.D and not bison.M for the case where subItemKey is empty because the whole sub-document match you are doing will fail if the fields are in the wrong order.

For the special case of searching for exact match, you can use the simplified format

    searchData = bson.D{{"data." + strings.ToLower(subItemKey), subItemString}}

It might not solve your problem but it does at least follow the recommended pattern.

If that does not fix your search, please add to your post the versions of the Mongo driver and database you are using, the full document you expect to retrieve, the declaration of the dataStruct type, and the initializer for the dataStruct that you are passing in.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks - there were a lot of people with similar answers, but you were first. Thanks for the help!
1

Given the struct Login

type Login struct {
    Email    string `json:"email"`
    Password string `json:"password"`
    Token    string `json:"token"`
}

Assuming you have data as

{data: {email: "[email protected]", password: "password", token: "token"}}

When subItemKey is blank, you're searching exactly like above. But when you search using only Email, the syntax should be

{"data.email": "[email protected]"}

But your code generates the search criteria as

{"data":{"email":{"$eq":"[email protected]"}}}

To make it work, change the line from

searchData, _ = bson.Marshal(bson.M{"data": bson.M{strings.ToLower(subItemKey): bson.M{"$eq": subItemString}}})

to

searchData, _ = bson.Marshal(bson.M{"data." + strings.ToLower(subItemKey): subItemString})

Comments

1

I think you want to search a nested property and therefore, you should change the query

This:

searchData, _ =  bson.Marshal(bson.M{"data": bson.M{strings.ToLower(subItemKey): bson.M{"$eq": subItemString}}})

To

nestedKey := fmt.Sprintf("data.%s", strings.ToLower(subItemKey))
searchData, _ = bson.Marshal(bson.M{nestedKey: subItemString})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.