Handle extra <<>> when elemMatch normalizes selector
When $elemMatch is applied to non-objects such as:
{"results":{"$elemMatch": {"$gte": 80, "$lt": 85}}},
our normalizer modifies the selector to include <<>>. This
causes issues for our path_str and match functions. This
fix addresses those issues by removing the <<>> from the selector
and also not adding a period when a Part is <<>>.
BugzId: 44817
diff --git a/src/mango_selector.erl b/src/mango_selector.erl
index c008a4c..21c55ae 100644
--- a/src/mango_selector.erl
+++ b/src/mango_selector.erl
@@ -411,6 +411,21 @@
match({[{<<"$all">>, _Args}]}, _Values, _Cmp) ->
false;
+%% This is for $elemMatch and possibly $in because of our normalizer.
+%% A selector such as {"field_name": {"$elemMatch": {"$gte": 80, "$lt": 85}}}
+%% gets normalized to:
+%% {[{<<"field_name">>,
+%% {[{<<"$elemMatch">>,
+%% {[{<<"$and">>, [
+%% {[{<<>>,{[{<<"$gte">>,80}]}}]},
+%% {[{<<>>,{[{<<"$lt">>,85}]}}]}
+%% ]}]}
+%% }]}
+%% }]}.
+%% So we filter out the <<>>.
+match({[{<<>>, Arg}]}, Values, Cmp) ->
+ match(Arg, Values, Cmp);
+
% Matches when any element in values matches the
% sub-selector Arg.
match({[{<<"$elemMatch">>, Arg}]}, Values, Cmp) when is_list(Values) ->
diff --git a/src/mango_selector_text.erl b/src/mango_selector_text.erl
index 74a4012..24d4ad1 100644
--- a/src/mango_selector_text.erl
+++ b/src/mango_selector_text.erl
@@ -274,7 +274,13 @@
% during recursion of convert.
[Part | Acc];
path_str([Part | Rest], Acc) ->
- path_str(Rest, [<<".">>, Part | Acc]).
+ case Part of
+ % do not append a period if Part is blank
+ <<>> ->
+ path_str(Rest, [Acc]);
+ _ ->
+ path_str(Rest, [<<".">>, Part | Acc])
+ end.
type_str(Value) when is_number(Value) ->
diff --git a/test/06-basic-text-test.py b/test/06-basic-text-test.py
index baf912b..670fad5 100644
--- a/test/06-basic-text-test.py
+++ b/test/06-basic-text-test.py
@@ -404,6 +404,24 @@
def setUpClass(klass):
raise unittest.SkipTest('text index is not supported yet')
+ def test_elem_match_non_object(self):
+ q = {"bestfriends":{
+ "$elemMatch":
+ {"$eq":"Wolverine", "$eq":"Cyclops"}
+ }
+ }
+ docs = self.db.find(q)
+ print len(docs)
+ assert len(docs) == 1
+ assert docs[0]["bestfriends"] == ["Wolverine", "Cyclops"]
+
+ q = {"results": {"$elemMatch": {"$gte": 80, "$lt": 85}}}
+
+ docs = self.db.find(q)
+ print len(docs)
+ assert len(docs) == 1
+ assert docs[0]["results"] == [82, 85, 88]
+
def test_elem_match(self):
q = {"friends": {
"$elemMatch":
diff --git a/test/friend_docs.py b/test/friend_docs.py
index 8bba58d..ec2c082 100644
--- a/test/friend_docs.py
+++ b/test/friend_docs.py
@@ -461,7 +461,8 @@
},
"type": "personal"
}
- ]
+ ],
+ "bestfriends" : ["Wolverine", "Cyclops"]
},
{
"_id": "54a431719faa420a5b4fbeb0",
@@ -530,6 +531,7 @@
"type": "work"
}
]
+ "results": [ 82, 85, 88 ]
},
{
"_id": "54a4317132f2c81561833259",