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

Mutual exclusive: key, keys, start_key and end_key #4414

Closed
wants to merge 1 commit into from

Conversation

jiahuili430
Copy link
Contributor

@jiahuili430 jiahuili430 commented Feb 3, 2023

Overview

  1. key behaves as if we set startkey=$key&endkey=$key. There is some confusion when we use them together. We should raise a 400 bad request when using key, keys, startkey and endkey together.

- Previous behavior:
When setting endkey to a, it will return doc a. But if we add key=c, it will rewrite startkey and endkey to c, then only doc c will be returned.

$ curl -XPUT $DB/db
$ curl -XPOST $DB/db/_bulk_docs -H 'Content-Type: application/json' -d '{"docs": [{"_id": "a"},{"_id": "b"},{"_id": "c"}]}'
$ curl $DB/db/_all_docs'?endkey="a"'
{"total_rows": 3, "offset": 0, "rows": [
    {"id": "a",
      "key": "a",
      "value": {"rev": "1-967a00dff5e02add41819138abb3284d"}
}]}

$ curl $DB/db/_all_docs'?endkey="a"&key="c"'
{"total_rows": 3, "offset": 2, "rows": [
    {"id": "c",
      "key": "c",
      "value": {"rev": "1-967a00dff5e02add41819138abb3284d"}
}]}

- After the change:

$ curl $DB/db/_all_docs'?endkey="b"&key="c"'
$ curl $DB/db/_all_docs'?keys=\["c"\]&startkey="b"'
$ curl $DB/db/_all_docs'?key="b"&keys=\["b"\]'
{
  "error": "query_parse_error",
  "reason": "`key`, `keys`, `start_key`, and `end_key` are incompatible"
}

  1. Add a flag enable_key_exclusivity to enable/disable mutual exclusivity for keys

  1. Execute a view with reduce function with key and single element keys, the response is different. We should treat one element keys the same as key and respond with the same result. If keys has multiple elements, it should behave as before.
$ curl -XDELETE $DB/db && curl -XPUT $DB/db
$ curl -XPOST $DB/db/_bulk_docs -H 'Content-Type: application/json' -d \
'{"docs": [{"key": "meatballs", "value": 1}, {"key": "spaghetti", "value": 2}, {"key": "tomato sauce", "value": 3}]}'
$ curl -XPOST $DB/db -H 'Content-Type: application/json' -d \
'{"_id": "_design/ddoc",
    "views": {
        "map_reduce": {
            "map": "function(doc) { emit(doc.key, doc.value) }",
            "reduce": "_sum"
}}}'

- Previous behavior:

$ curl $DB/db/_design/ddoc/_view/map_reduce'?key="meatballs"'
{"rows":[{"key":null,"value":1}]}

$ curl $DB/db/_design/ddoc/_view/map_reduce'?keys=\["meatballs"\]'
{
  "error": "query_parse_error",
  "reason": "Multi-key fetchs for reduce views must use `group=true`"
}

$ curl $DB/db/_design/ddoc/_view/map_reduce'?keys=\["meatballs"\]&group=true'
{"rows":[{"key":"meatballs","value":1}]}

$ curl $DB/db/_design/ddoc/_view/map_reduce'?keys=\["meatballs","spaghetti"\]'
{
  "error": "query_parse_error",
  "reason": "Multi-key fetchs for reduce views must use `group=true`"
}

- After the change:

$ curl $DB/db/_design/ddoc/_view/map_reduce'?key="meatballs"'
{"rows":[{"key":null,"value":1}]}

$ curl $DB/db/_design/ddoc/_view/map_reduce'?keys=\["meatballs"\]'
{"rows":[{"key":null,"value":1}]}

$ curl $DB/db/_design/ddoc/_view/map_reduce'?keys=\["meatballs"\]&group=true'
{"rows":["key":"meatballs","value":1}]}

$ curl $DB/db/_design/ddoc/_view/map_reduce'?keys=\["meatballs","spaghetti"\]'
{
  "error": "query_parse_error",
  "reason": "Multi-key fetches for reduce views must use `group=true`"
}

Testing recommendations

make eunit apps=chttpd,couch_mrview

Related Issues or Pull Requests

Fix #3977, #2243

Checklist

  • Code is written and works correctly
  • Changes are covered by tests
  • Any new configurable parameters are documented in rel/overlay/etc/default.ini
  • Documentation changes were made in the src/docs folder
  • Documentation changes were backported (separated PR) to affected branches

@rnewson
Copy link
Member

rnewson commented Feb 3, 2023

I like the clarity of the new errors but do not think we should combine key and keys. in my opinion that should be a 400 Bad Request.

@jiahuili430 jiahuili430 closed this Feb 3, 2023
@jiahuili430 jiahuili430 reopened this Feb 3, 2023
@nickva
Copy link
Contributor

nickva commented Feb 6, 2023

There is a related issue about how key=onekey vs keys=[onekey] behaves with grouping #2243.

@jiahuili430 jiahuili430 marked this pull request as draft February 27, 2023 22:38
@jiahuili430 jiahuili430 force-pushed the keys-mutually-exclusive branch 6 times, most recently from 869e4c2 to a1344d4 Compare March 4, 2023 23:29
@jiahuili430 jiahuili430 changed the title key(s) should incompatible with start_key and end_key Mutual exclusive: key, keys, start_key and end_key Mar 5, 2023
@jiahuili430 jiahuili430 marked this pull request as ready for review March 5, 2023 01:14
@jiahuili430 jiahuili430 force-pushed the keys-mutually-exclusive branch 2 times, most recently from d5d0f2c to 465468f Compare March 6, 2023 17:08
@jiahuili430 jiahuili430 force-pushed the keys-mutually-exclusive branch 5 times, most recently from 6646728 to a9ea220 Compare March 14, 2023 23:14
@nickva
Copy link
Contributor

nickva commented Mar 17, 2023

If we plan on toggling this on in 4.x we should add it to #4480 and make a note in docs about the new setting. Some users may want to enable it in 3.x already.

Copy link
Contributor

@nickva nickva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

Great tests. Just had a few question and a suggestion to simplify the exclusivity check.

src/couch_mrview/src/couch_mrview_http.erl Outdated Show resolved Hide resolved
src/couch_mrview/src/couch_mrview_util.erl Show resolved Hide resolved
src/couch_mrview/src/couch_mrview_util.erl Show resolved Hide resolved
src/chttpd/test/eunit/chttpd_view_test.erl Show resolved Hide resolved
src/chttpd/test/eunit/chttpd_view_test.erl Outdated Show resolved Hide resolved
src/couch_mrview/src/couch_mrview_http.erl Outdated Show resolved Hide resolved
src/couch_mrview/src/couch_mrview_http.erl Outdated Show resolved Hide resolved
src/couch_mrview/src/couch_mrview_http.erl Outdated Show resolved Hide resolved
@jiahuili430 jiahuili430 force-pushed the keys-mutually-exclusive branch 2 times, most recently from aa877e8 to 0adbf34 Compare March 20, 2023 19:23
@jiahuili430 jiahuili430 force-pushed the keys-mutually-exclusive branch 4 times, most recently from 70fb063 to 44a1028 Compare March 23, 2023 12:22
- Key and Keys should be incompatible with start_key and end_key
- Execute a reduced views, treat a single element keys as the key
- Add flag `enable_key_exclusivity` to enable key incompatibility with
start_key and end_key
Copy link
Member

@rnewson rnewson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm -0 on the behaviour change behind the exclusivity flag. I'd rather not have it, but I am not vetoing.

My reasoning is 1) It's disabled by default because 2) it will convert successful requests to failures 3) it will be a long time, if ever, before CouchDB will flip the default 4) It only fixes a subset of the validation issues in the _view endpoint.

I'd rather see us document the actual behaviour, silly as it is.

I'm fine with the part of the PR that treats a single item keys parameter as if you did key, since this transforms a current failure into success and (importantly) yielding the correct answer.

I've made a few specific comments on the diff.

@@ -530,9 +551,20 @@ parse_param(Key, Val, Args, IsDecoded) ->
JsonKey = ?JSON_DECODE(Val),
Args#mrargs{start_key = JsonKey, end_key = JsonKey};
"keys" when IsDecoded ->
Args#mrargs{keys = Val};
case Val of
[Val1] ->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Key would be a better name for Val1 here.

Copy link
Contributor Author

@jiahuili430 jiahuili430 Mar 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your comments, I tried to rewrite this PR here #4494
Changed [Val1] to [SingleKeys] because Key is already used.

Args#mrargs{keys = ?JSON_DECODE(Val)};
Val1 = ?JSON_DECODE(Val),
case Val1 of
[Val2] ->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Key would be a better name for Val2 here. I'd also inline the ?JSON_DECODE so we don't need a Val1

@jiahuili430
Copy link
Contributor Author

Close this PR as #4494 has been merged.

@jiahuili430 jiahuili430 closed this Apr 5, 2023
@jiahuili430 jiahuili430 deleted the keys-mutually-exclusive branch April 5, 2023 13:17
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

Successfully merging this pull request may close these issues.

key vs endkey
4 participants