diff options
author | Will Holley <willholley@gmail.com> | 2018-05-23 15:01:49 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-23 15:01:49 +0100 |
commit | 8e28fd2af5732d1b7e2866977860695fcbd676e8 (patch) | |
tree | ab0df1fd49eeacb4bdce92fa2d78cb2f6e67bd17 | |
parent | f541e48a76e26945440d370235b53ab7310d1476 (diff) | |
download | couchdb-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.erl | 8 | ||||
-rw-r--r-- | src/mango/test/12-use-correct-index-test.py | 13 |
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') |