Elasticsearch: range query for count of nested array matches - elasticsearch

I'm storing room objects in an index like this:
{
"name":"room1",
"availability":"10",
"reservations": [
{
"start_date": "2019-09-12",
"end_date": "2019-09-15",
},
{
"start_date": "2019-09-17",
"end_date": "2019-09-19"
}
]}
Given a new startDate and endDate,
how can I match all rooms where room.availability is greater than the
number of reservations that overlap with these dates?

Have you tried using a range query and a script query to only return the document according to your predicate ?
elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-query.html

Related

Filter with complex key not work (using startkey and endkey)

I create a view with Map function:
function(doc) {
if (doc.market == "m_warehouse") {
emit([doc.logTime,doc.dbName,doc.tableName], 1);
}
}
I want to filter the data with multi-keys:
_design/select_data/_view/new-view/?limit=10&skip=0&include_docs=false&reduce=false&descending=true&startkey=["2018-06-19T09:16:47,527","stage"]&endkey=["2018-06-19T09:16:43,717","stage"]
but I still got:
{
"total_rows": 248133,
"offset": 248129,
"rows": [
{
"id": "01CGBPYVXVD88FPDVR3NP50VJW",
"key": [
"2018-06-19T09:16:47,527",
"ods",
"o_ad_dsp_pvlog_realtime"
],
"value": 1
},
{
"id": "01CGBQ6JMEBR8KBMB8T7Q7CZY3",
"key": [
"2018-06-19T09:16:44,824",
"stage",
"s_ad_ztc_realpv_base_indirect"
],
"value": 1
},
{
"id": "01CGBQ4BKT8S2VDMT2RGH1FQ71",
"key": [
"2018-06-19T09:16:44,707",
"stage",
"s_ad_ztc_realpv_base_indirect"
],
"value": 1
},
{
"id": "01CGBQ18CBHQX3F28649YH66B9",
"key": [
"2018-06-19T09:16:43,717",
"stage",
"s_ad_ztc_realpv_base_indirect"
],
"value": 1
}
]
}
the key "ods" should not in the results.
What did I do wrong?
Your query is not multi-key .. ist start and endkey.
if you want to have results by dbname in a special time range.. you need to change the emit to [doc.dbName,doc.logTime,doc.tableName]
then you query startkey=["stage","2018-06-19T09:16:43,717"]&endkey=["stage","2018-06-19T09:16:47,527"]
(btw. are you sure that your timestamp is in the right order ? In your example the second TS is larger than the first..)
As you have chosen a full date/time stamp as the first level of your key, down to millisecond precision, there are unlikely to be any repeating values in the first level of your compound key. If you indexed just the date, say, as the first key, your date would be grouped by date, dbame and table name in a more predictable way
e.g.
["2018-06-19","ods","o_ad_dsp_pvlog_realtime"]
["2018-06-19","stage","s_ad_ztc_realpv_base_indirect"]
["2018-06-19",stage","s_ad_ztc_realpv_base_indirect"
["2018-06-19","stage","s_ad_ztc_realpv_base_indirect"
With this key structure, the hierarchical grouping of keys works in your favour i.e. all the data from "2018-06-19" is together in the index, with all the data matching ["2018-06-19","stage"] adjacent to each other.
If you need to get to millisecond precision, you could index the data as follows:
function(doc) {
if (doc.market == "m_warehouse") {
emit([doc.dbName,doc.logTime], 1);
}
}
This would create index organised by dbName, but with a secondary sort on time. You can then extract the data for specified dbName between two timestamps.

Count Unique Objects

My index looks like this:
"_source": {
"ProductName": "Random Product Name",
"Views": {
"Washington": [
{ "4nce5bbszjfppltvc": "2018-04-07T18:25:16.160Z" },
{ "4nce5bba8jfpowm4i": "2018-04-07T18:05:39.714Z" },
{ "4nce5bbszjfppltvc": "2018-04-07T18:36:23.928Z" },
]
}
}
I am trying to count the number of unique objects in Views.Washington.
In this case, the result would be 2, since two objects have the same key names. ( first and third object in the array ).
Obviously, my first thought was to use aggregations, but I am not sure how to use them with nested objects, like these.
Can this be done with normal aggregations?
Will I need to use a script?
Yes this can be done with Aggregations: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-nested-aggregation.html

How to get all maxes from couchbase using map/reduce?

I've got a lot of records like:
{
"id": "1000",
"lastSeen": "2018-02-26T18:49:21.863Z"
}
{
"id": "1000",
"lastSeen": "2017-02-26T18:49:21.863Z"
}
{
"id": "2000",
"lastSeen": "2018-02-26T18:49:21.863Z"
}
{
"id": "2000",
"lastSeen": "2017-02-26T18:49:21.863Z"
}
I'd like to get the most recent records for all ids. So in this case the output would be the following(most recent record for ids 1000 and 2000):
{
"id": "1000",
"lastSeen": "2018-02-26T18:49:21.863Z"
}
{
"id": "2000",
"lastSeen": "2018-02-26T18:49:21.863Z"
}
With N1QL, this would be
SELECT id, MAX(lastSeen) FROM mybucket GROUP BY id
How would I do this using a couchbase view and map/reduce?
Thanks!
I am far from a regular user of map/reduce, and there may be more efficient JavaScript, but try this:
Map
function (doc, meta) {
emit(doc.id, doc.lastSeen);
}
Reduce
function reduce(key, values, rereduce) {
var max = values.sort().reverse()[0];
return max;
}
Filter: ?limit=6&stale=false&connection_timeout=60000&inclusive_end=true&skip=0&full_set=true&group_level=1
The idea is to sort all the values being emitted (lastSeen). Since they are ISO 8601 and can be lexigraphically sorted, sort() works just fine. You want the latest, so that's what the reverse() is for (otherwise you'd get the oldest).
The filter has a group_level of 1, so it will group by the doc.id field.
You can query by descending and reduce to first one on list as below:
Map:
function (doc, meta) {
emit(doc.id, doc.lastSeen);
}
Reduce:
function reduce(key, values, rereduce) {
return values[0];
}
Filter:
?inclusive_end=true&skip=0&full_set=&group_level=1&descending=true
This will eliminate the overhead of sorting the grouped values inside reduce function.

Query least one item of array Elasticsearch

Suppose I have documents like this:
{
"name":"Foo",
"interests":{
"movies":[
1,
2,
3
],
"music":[
8,
9,
10
]
}
}
How do I query for documents that match at least one of array items given an integer number?
Example: How to query all documents that interests.movie has 1?
All query examples I had tried turned into an exclusive match.
Pretty much how you described:
GET movies/_search
{
"query": {
"match": {
"interests.movies": "1"
}
}
}

couchDB- complex query on a view

I am using cloudantDB and want to query a view which looks like this
function (doc) {
if(doc.name !== undefined){
emit([doc.name, doc.age], doc);
}
what should be the correct way to get a result if I have a list of names(I will be using option 'keys=[]' for it) and a range of age(for which startkey and endkey should be used)
example: I want to get persons having name "john" or "mark" or "joseph" or "santosh" and lie between age limit 20 to 30.
If i go for list of names, query should be keys=["john", ....]
and if I go for age query should use startkey and endkey
I want to do both :)
Thanks
Unfortunately, you can't do so. Using the keys parameter query the documents with the specified key. For example, you can't only send keys=["John","Mark"]&startkey=[null,20]&endkey=[{},30]. This query would only and ONLY return the document having the name John and Mark with a null age.
In your question you specified CouchDB but if you are using Cloudant, index query might be interesting for you.
You could have something like that :
{
"selector": {
"$and": [
{
"name": {
"$in":["Mark","John"]
}
},
{
"year": {
"$gt": 20,
"$lt": 30
}
}
]
},
"fields": [
"name",
"age"
]
}
As for CouchDB, you need to either separate your request (1 request for the age and 1 for the people) or you do the filtering locally.

Resources