Query index in Cloudant doesn't return expected data - indexing

I have a Cloudant DB on Bluemix with an index defined as:
{
"index": {
"fields": [
{ "typ": "asc" },
{ "sen": "asc" },
{ "tim": "asc" }
]
},
"type": "json"
}
WHen I have a query of the form
{
"selector": {
"tim": {"$gt": millisecs},
"typ": "H"
},
"fields": ["sen","val","tim"],
"sort": [
{ "typ": "asc" },
{ "sen": "asc" },
{ "tim": "asc" }
],
"limit": readCount
}
it works perfectly. If I want to get everything, i.e. remove the condition typ="H", I get the error
"error":"no_usable_index","reason":"There is no index available for this selector."
I get the same response if I have "typ" : { "$in": ["H", "T"] }. I would have expected that the more generic query would work better than the one with extra selectors.
I just don't understand how this could be!

"typ" is the first field of your index, so is the basis of the ordering.
"tim", if it's the only element of the query, doesn't take advantage of the index, so it would trigger a full table scan if that query was allowed.
However you can ask explicitely for a full table scan if you add:
"_id": { "$gt": null }
See the doc, your case is not really described, but I think it's implied.

Did you try to create separate indexes for these fields and run the same query?

Related

Only structured queries are supported FIRESTORE API REST

I am trying to run a query with the rest api but I canĀ“t get it to work, I am sending this body in json:
"structuredQuery": {
"where": {
"fieldFilter": {
"field": {
"fieldPath": "total"
},
"op": "EQUAL",
"value": {
"integerValue": "10",
}
}
},
"from": [{
"collectionId": "Total"
}]
}
I am just testing if querys work, I have a collection called Total with documents, and these documents have a field called total that is an integer value. I am using a POST request with the following URL:
"https://firestore.googleapis.com/v1/projects/MY_PROJECT_NAME/databases/(default)/documents:runQuery"
and I am getting this error:
[{
"error": {
"code": 400,
"message": "only structured queries are supported",
"status": "INVALID_ARGUMENT"
}
}]
The CollectionSelector in your structured query is missing the allDescendants field.
If you check this documentation you can see that this field is a flag which can either be true or false but not null, so you have to set this in the query otherwise it will not work.
Also you need to add the select clause to add all fields you want to get as a result of the query or keep it empty to return all fields.
Finally in the said documentation you can check that there is a proper order that should be respected, in which the from must be declared before where. So if you change your structured query to the following:
"structuredQuery": {
"from": [{
"collectionId": "Total"
"allDescendants": false
}],
"select": { "fields": [] },
"where": {
"fieldFilter": {
"field": {
"fieldPath": "total"
},
"op": "EQUAL",
"value": {
"integerValue": "10",
}
}
}
}
It will work as expected.

how to select a single item and get it's relations in faunadb?

I have two collections which have the data in the following format
{
"ref": Ref(Collection("Leads"), "267824207030650373"),
"ts": 1591675917565000,
"data": {
"notes": "voicemail ",
"source": "key-name",
"name": "Glenn"
}
}
{
"ref": Ref(Collection("Sources"), "266777079541924357"),
"ts": 1590677298970000,
"data": {
"key": "key-name",
"value": "Google Ads"
}
}
I want to be able to query the Leads collection and be able to retrieve the corresponding Sources document in a single query
I came up with the following query to try and use an index but I couldn't get it to run
Let(
{
data: Get(Ref(Collection('Leads'), '267824207030650373'))
},
{
data: Select(['data'],Var('data')),
source: q.Lambda('data',
Match(Index('LeadSourceByKey'), Get(Select(['source'], Var('data') )) )
)
}
)
Is there an easy way to retrieve the Sources document ?
What you are looking for is the following query which I broke down for you in multiple steps:
Let(
{
// Get the Lead document
lead: Get(Ref(Collection("Leads"), "269038063157510661")),
// Get the source key out of the lead document
sourceKey: Select(["data", "source"], Var("lead")),
// use the index to get the values via match
sourceValues: Paginate(Match(Index("LeadSourceValuesByKey"), Var("sourceKey")))
},
{
lead: Var("lead"),
sourceValues: Var("sourceValues")
}
)
The result is:
{
lead: {
ref: Ref(Collection("Leads"), "269038063157510661"),
ts: 1592833540970000,
data: {
notes: "voicemail ",
source: "key-name",
name: "Glenn"
}
},
sourceValues: {
data: [["key-name", "Google Ads"]]
}
}
sourceValues is an array since you specified in your index that there will be two items returned, the key and the value and an index always returns the array. Since your Match could have returned multiple values in case it wasn't a one-to-one, this becomes an array of an array.
This is only one approach, you could also make the index return a reference and Map/Get to get the actual document as explained on the forum.
However, I assume you asked the same question here. Although I applaud asking questions on stackoverflow vs slack or even our own forum, please do not just post the same question everywhere without linking to the others. This makes many people spend a lot of time while the question is already answered elsewhere.
You might probably change the Leads document and put the Ref to Sources document in source:
{
"ref": Ref(Collection("Leads"), "267824207030650373"),
"ts": 1591675917565000,
"data": {
"notes": "voicemail ",
"source": Ref(Collection("Sources"), "266777079541924357"),
"name": "Glenn"
}
}
{
"ref": Ref(Collection("Sources"), "266777079541924357"),
"ts": 1590677298970000,
"data": {
"key": "key-name",
"value": "Google Ads"
}
}
And then query this way:
Let(
{
lead: Select(['data'],Get(Ref(Collection('Leads'), '267824207030650373'))),
source:Select(['source'],Var('lead'))
},
{
data: Var('lead'),
source: Select(['data'],Get(Var('source')))
}
)

Using $or selector, There is no index available for this selector

I'd like to retrieve
document with _id of 1
OR
document with value === 13 AND anotherValue === 56
Error:
There is no index available for this selector.
This is my query:
{
"selector": {
"$or": [
{
"_id": "1"
},
{
"value": "13",
"anotherValue": "56"
}
]
}
}
Indexes setup:
Your available Indexes:
special: _id
json: value, anotherValue
json: _id, value, anotherValue
For this query you need to add a selector to get all the IDs like so:
{
"selector": {
"_id": {"$gt":null},
"$or": [
{
"_id": "1"
},
{
"value": "13",
"anotherValue": "56"
}
]
}
}
You can learn more here:
https://cloudant.com/blog/mango-json-vs-text-indexes/
And this SO post:
index and query items in an array with mango query for cloudant and couchdb 2.0
Alternatively, you can add a text index on all fields:
{
"index": {},
"type": "text"
}
And then your original selector should work.

Sorting ElasricSearch based on size of array type field

I have a ElasticSearch cluster on which I have to perform a sort query based on the size of the object array field 'contents'.
So far I have tried,
{
"size": 10,
"from": 0,
"fields" : ['name'],
"query": {
"match_all": {}
},
"sort" : {
"script" : {
"script" : "doc['contents'].values.length",
"order": "desc"
}
}
}
The above query gives me SearchPhaseExecutionException. The ES query is made from client side using elasticsearch.angular.js.
Any kind of help will be appreciate.
The security has changed for scripts in versions 1.2.x. In ES_HOME/config/scripts create a file called script_score.mvel and add the script:
doc.containsKey('content') == false ? 0 : doc['content'].values.size()
Restart Elasticsearch and change your query to:
{
"size": 10,
"from": 0,
"query": {
"match_all": {}
},
"sort": {
"_script": {
"script": "script_score",
"order": "desc",
"type" : "string"
}
}
}
For more information take a look here:
http://www.elasticsearch.org/blog/scripting-security/

Elasticsearch/Tire text query DSL for excluding certain fields from being searched

I have a elastic search query like the following,
{
"query": {
"bool": {
"must": [
{
"query_string": {
"fields": ["title"],
"query": "test"
}
}
],
"must_not": [],
"should": []
}
},
"from": 0,
"size": 50,
"sort": [],
"facets": {}
}
I am able to execute an elastic search query on certain fields by giving a fields param to query_string as mentioned above. In my index mapping i have around 50 fields indexed. How do i query for all but one field. Something like an exclude option to query string. Is it possible with Tire/Elastic Search ?
I assumed it cannot be done and proceeded with getting all the mappings and parsing the hash which kinda sucks actually.