summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Holley <willholley@gmail.com>2018-05-23 15:01:49 +0100
committerGitHub <noreply@github.com>2018-05-23 15:01:49 +0100
commit8e28fd2af5732d1b7e2866977860695fcbd676e8 (patch)
treeab0df1fd49eeacb4bdce92fa2d78cb2f6e67bd17
parentf541e48a76e26945440d370235b53ab7310d1476 (diff)
downloadcouchdb-8e28fd2af5732d1b7e2866977860695fcbd676e8.tar.gz
Mango: _id and _rev index selection
Mango requires that a JSON index can only be used to fulfil a query if the "selector" field covers all of the fields the index. For example, if an index contains ["a", "b"] but the selector only requires field ["a"] to exist in the matching documents, the index would not be valid for the query (because it only includes documents containing both "a" and "b"). There is a special case here around built-in fields; _id and _rev specifically, because they are guaranteed to exist in any matching documents. If a user declares an index ["a", "_id"], we can safely exclude "_id" from the index coverage check, so a selector of {"a": "foo"} should be able to use this index. Prior to this commit, a user would have to alter the selector so that it covered the "_id" field, e.g. {"a": "foo", "_id": {"$exists": true}}. The commit removes the need to explicitly cover _id or _rev fields in the query selector.
-rw-r--r--src/mango/src/mango_idx_view.erl8
-rw-r--r--src/mango/test/12-use-correct-index-test.py13
2 files changed, 20 insertions, 1 deletions
diff --git a/src/mango/src/mango_idx_view.erl b/src/mango/src/mango_idx_view.erl
index c9fe4c85d..8956b27b0 100644
--- a/src/mango/src/mango_idx_view.erl
+++ b/src/mango/src/mango_idx_view.erl
@@ -124,7 +124,13 @@ is_usable(Idx, Selector, SortFields) ->
% we don't need to check the selector for these
RequiredFields1 = ordsets:subtract(lists:usort(RequiredFields), lists:usort(SortFields)),
- mango_selector:has_required_fields(Selector, RequiredFields1)
+ % _id and _rev are implicitly in every document so
+ % we don't need to check the selector for these either
+ RequiredFields2 = ordsets:subtract(
+ RequiredFields1,
+ [<<"_id">>, <<"_rev">>]),
+
+ mango_selector:has_required_fields(Selector, RequiredFields2)
andalso not is_text_search(Selector).
diff --git a/src/mango/test/12-use-correct-index-test.py b/src/mango/test/12-use-correct-index-test.py
index 5a2b24d3f..7bb90ebf9 100644
--- a/src/mango/test/12-use-correct-index-test.py
+++ b/src/mango/test/12-use-correct-index-test.py
@@ -114,3 +114,16 @@ class ChooseCorrectIndexForDocs(mango.DbPerClass):
explain = self.db.find(selector, explain=True)
self.assertEqual(explain["index"]["ddoc"], "_design/bbb")
self.assertEqual(explain["mrargs"]["end_key"], [10, '<MAX>'])
+
+ # all documents contain an _id and _rev field they
+ # should not be used to restrict indexes based on the
+ # fields required by the selector
+ def test_choose_index_with_id(self):
+ self.db.create_index(["name", "_id"], ddoc="aaa")
+ explain = self.db.find({"name": "Eddie"}, explain=True)
+ self.assertEqual(explain["index"]["ddoc"], '_design/aaa')
+
+ def test_choose_index_with_rev(self):
+ self.db.create_index(["name", "_rev"], ddoc="aaa")
+ explain = self.db.find({"name": "Eddie"}, explain=True)
+ self.assertEqual(explain["index"]["ddoc"], '_design/aaa')