Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More complex documents can not be queried properly #143

Open
rababarber opened this issue Oct 23, 2017 · 3 comments
Open

More complex documents can not be queried properly #143

rababarber opened this issue Oct 23, 2017 · 3 comments

Comments

@rababarber
Copy link

I'm experiencing strange behaviour when trying to query more complex JSON documents in embedded mode. When the document that is inserted inserted to tiedot is created from a string via json.Unmarshal() it can be queried successfully. In case it is created from a directly initialized object it can not be queried.

Example object is taken from the example in documentation:

{"Name": [
  {"PenName": "Joshua"}, 
  {"PenName": ["John", "David"]}
]}

Consider the following code snippet:

_, err = coll.Insert(jsonDoc)

query := map[string]interface{}{
	"eq": "John",
	"in": []interface{}{"Name", "PenName"},
}

queryResult := make(map[int]struct{})
if err := db.EvalQuery(query, coll, &queryResult); err != nil {
	panic(err)
}

Query returns any data only in a case when jsonDoc is created as:

s := `{"Name": [{"PenName": "Joshua"}, {"PenName": ["John", "David"]}]}`
var jsonDoc map[string]interface{}
json.Unmarshal([]byte(s), &jsonDoc)

but does not work when created as:

jsonDoc := map[string]interface{}{
  "Name": []interface{}{
    map[string]interface{}{
      "PenName": "Joshua",
    },
    map[string]interface{}{
      "PenName": []string{"John", "David"},
    },
  },
}

From my understanding these two methods of creating jsonDoc are equivalent. What I'm missing?

@rababarber
Copy link
Author

rababarber commented Oct 23, 2017

On further comparison of the objects created by direct initialization and json.Unmarshal I found that []string needs to be declared as []interface{} in order for the inserted object to be queryable.
i.e. the object needs to be declared as:

jsonDoc := map[string]interface{}{
  "Name": []interface{}{
    map[string]interface{}{
      "PenName": "Joshua",
    },
    map[string]interface{}{
      "PenName": []interface{}{"John", "David"},
    },
  },
}

which is, IMHO, rather unintuitive.

@HouzuoGuo
Copy link
Owner

Hello!

Terribly sorry about the inconvenience, here's the culprit:

https://github.com/HouzuoGuo/tiedot/blob/master/db/doc.go#L14

The function works very well for JSON documents deserialised from string, but as you have observed, unfortunately it does not have a match for []string.

Reflection may come in handy in this case, but I have yet to understand the performance implication of reflection vs type matching.

@rababarber
Copy link
Author

rababarber commented Oct 24, 2017

Thanks for the explanation.

On a second thought this might be not that big of a problem in practice as people will be mostly (i would guess) piping the structs to be stored via json.Marshal -> json.Unmarshal to have map[string]interface{} for Insert method and this takes care of passing arrays correctly.

I found this when writing simple test program for tiedot evaluation and initialized map[string]interface{} variable with data directly.

Maybe it would make sense to mention this in documents (or embedded usage tutorial) somehow, but I do not have a good proposal how and where in particular.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants