rs / rest-layer

REST Layer, Go (golang) REST API framework

Home Page: http://rest-layer.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Behaviour of query/predicate does not match behaviour of MongoDB storage backend

torie opened this issue · comments

The behaviour of the filter operators in the query package does not work when the document field being matched against is an array. For example, given the following document and query, the MongoDB storage backend will return a match, while the resource/testing/mem backend will not.

Document

{ "foo": ["bar", "baz"] }

Query

{ field: { $in: ["bar"] } }

This is the case for the following operators, $eq, $in $ne, $nin.

Support for $in and $nin added in #188.
Support for $eq and $ne still need to be updated.

Accidentally clicked the close button...

I guess I can take on this.

Hmm, that is strange. First there is no $eq operator in rest-layer. I added these tests in predicate_test.go and they are seem to be passing. I will test with real resource tomorrow, though.

		{
			`{"foo":["bar","baz"]}`, []test{
				{map[string]interface{}{"foo": []interface{}{"bar", "baz"}}, true},
				{map[string]interface{}{"foo": []interface{}{"bar"}}, false},
				{map[string]interface{}{"foo": []interface{}{"baz"}}, false},
				{map[string]interface{}{"foo": []interface{}{"bar", "baz", "tar"}}, false},
				{map[string]interface{}{"foo": []interface{}{}}, false},
			},
			nil,
		},
		{
			`{"foo":{$ne: ["bar","baz"]}}`, []test{
				{map[string]interface{}{"foo": []interface{}{"bar", "baz"}}, false},
				{map[string]interface{}{"foo": []interface{}{"bar"}}, true},
				{map[string]interface{}{"foo": []interface{}{"baz"}}, true},
				{map[string]interface{}{"foo": []interface{}{"bar", "baz", "tar"}}, true},
				{map[string]interface{}{"foo": []interface{}{}}, true},
			},
			nil,
		},

@torie Any comment appreciated.

{
	`{"foo":"bar"}`, []test{
		{map[string]interface{}{"foo": []interface{}{"bar", "baz"}}, true},
		{map[string]interface{}{"foo": []interface{}{"bar"}}, true},
		{map[string]interface{}{"foo": []interface{}{"baz"}}, false},
		{map[string]interface{}{"foo": []interface{}{"bar", "baz", "tar"}}, true},
		{map[string]interface{}{"foo": []interface{}{}}, false},
	},
	nil,
},
{
	`{"foo":{$ne: "bar"}}`, []test{
		{map[string]interface{}{"foo": []interface{}{"bar", "baz"}}, false},
		{map[string]interface{}{"foo": []interface{}{"bar"}}, false},
		{map[string]interface{}{"foo": []interface{}{"baz"}}, true},
		{map[string]interface{}{"foo": []interface{}{"bar", "baz", "tar"}}, false},
		{map[string]interface{}{"foo": []interface{}{}}, true},
	},
	nil,
},

The idea is what happens when you do a non-array query against an array field with MongDB:

https://docs.mongodb.com/manual/tutorial/query-arrays/#query-an-array-for-an-element

The idea is for the mem-backend and MongoDB backend to behave consistently for this cases. So that unit-tests are likely to match with MongoDB results (in production).

Okay, it checks if the value is in/not-in the array. Will implement this.

For the $ne case in particular, it's worth double checking what the MongoDB implementation actually does before implementing.

The equal case is well documented in the linked docs, so that should be OK. I think we also tested this for equal, although we only needed it for $in and $nin when we did the first query.