Why does this ES multi-match query return a 400 error (bad request)?
"query": {
"multi_match": {
"query": searchTerms,
"fields": ["content", "title"],
"operator": "and"
}
},
size: 100,
from: 0,
highlight: {
fields: {
"title": {number_of_fragments: 0},
"content": {number_of_fragments: 10,fragment_size: 300}
}
}
}
I'm using this query in conjunction with AngularJS UI Bootstrap Typeahead code like this
uib-typeahead="query as query._source.ymme for query in getSuggestions($viewValue)" typeahead-on-select="search($item)"
This is my search() function
$scope.search = function() {
console.log($scope.searchTerms);
$scope.currentPage = 0;
$scope.results.documents = [];
$scope.isSearching = true;
return searchService.search($scope.searchTerms, $scope.currentPage).then(function(es_return) {
var totalItems = es_return.hits.total;
var totalTime = es_return.took;
var numPages = Math.ceil(es_return.hits.total / $scope.itemsPerPage);
$scope.results.pagination = [];
for (var i = 1; i <= 100; i++) {
if(totalItems > 0)
$scope.results.totalItems = totalItems;
$scope.results.queryTime = totalTime;
$scope.results.pagination = searchService.formatResults(es_return.hits.hits);
$scope.results.documents = $scope.results.pagination.slice($scope.currentPage, $scope.itemsPerPage);
}
}
),
function(error){
console.log('ERROR: ', error.message);
$scope.isSearching = false;
}
};
I'm not quite sure what is wrong? I'm thinking it has something to do with $scope, but I'm not sure. The query works when I use it Sense plugin for ES and it also works if I just type in a search term instead of selecting it from the autocomplete dropdown.
If it is $scope, what am I missing?
UPDATE
All shards failed for phase: [query_fetch]
org.elasticsearch.search.SearchParseException: [hugetestindex][0]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"query":{"multi_match":{"query":{"_index":"hugetestindex","_type":"doc","_id":"57","_score":3.877801,"_source":{"ymme":"bourne supremacy"}},"fields":["content","title"],"operator":"and"}},"size":100,"from":0,"highlight":{"fields":{"title":{"number_of_fragments":0},"content":{"number_of_fragments":10,"fragment_size":300}}}}]]
UPDATE 2 Object {_index: "hugetestindex", _type: "doc", _id: "56", _score: 2.5276248, _source: Object}
I think that is the problem, instead of a search terms, its receiving "Object"....?
UPDATE 3So basically it goes like this,
[Object, Object, Object, Object, Object]
0: Object
_id: "229"
_index: "hugetestindex"
_score: 3.3071127
_source: Object
ymme: "bourne supremacy"
__proto__: Object
_type: "doc"
__proto__:
Object1:
Object2:
Object3:
Object4:
Object
length: 5
__proto__: Array[0]
where "bourne supremacy" is the value of the ymme field in the _source Object, the array at the top with the 5 objects is the es return, es_return.hits.hits - this last hits, is the array.
The way you deconstruct your object is by doing something like the following:
object.data.hits.hits._source.field_name;
The above is only a notation to get the value of a single field, you might need to do a loop for each of those values so maybe something like:
$scope.list = []
for hit in object.data.hits.hits {
$scope.list.push(hit._source.field);
}
console.log(list);
Then from your HTML you want to use this list by doing an ng-repeat with it or something similar to get each of the terms in the list.
<div ng-repeat="term in list">{{term}}</div>
If you can update your question with how your object looks and what data you want from it, I can update this answer to match it exactly.
UPDATE
To match your data structure, I'm assuming you want to extract each of the ymme values from those objects. You need to do the following:
<div ng-repeat="object in es_return.hits.hits">
{{object._source.ymme}}
</div>
Just make sure "es_return" is a $scope variable so you can access it as above or just do:
$scope.es_return = es_return;
In your Angular code
I wanna add an object to an array but I don't know how to declare a variable with the return type is Array<object>.
My example:
var obj = {
'Prop name': 'Prop value'
};
document.body.innerHTML = typeof obj; // output: object
var arr: Array<object>; // error message: Cannot find name 'object'
arr.push(obj);
I've tried again with:
var obj: Object = {
'Prop name': 'Prop value'
};
document.body.innerHTML = typeof obj; // output: object
var arr: Array<Object>;
arr.push(obj); // error message: Cannot read property 'push' of undefined
How can I fix the issue?
The first error is because it's Object (title case) not object (lower case)
The second error is because you've typed the variable, but not actually assigned an instance. Try:
var arr: Array<Object> = [];
arr.push(obj);
You miss initialization of arr array:
var obj: Object = {
'Prop name': 'Prop value'
};
document.body.innerHTML = typeof obj; // output: object
var arr: Array<Object> = []; // MODIFIED
arr.push(obj);
You should use Object or any instead:
var arr: Array<any>;
I have JSON object in the below format,
$scope.indexData = {
"custid": "1",
"addresses": [
{
"addressType": "P",
"address1": ""
},
{
"addressType": "M"
}
],
"personalDetails": {
"title": "",
"name": ""
}
}
I want to store the object using HTML5 indexDB. how do i store the object?
I tried in the following way, but no luck.
var db;
var request = window.indexedDB.open("newDatabase", 1);
request.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore = db.createObjectStore("customers");
for (var i in $scope.indexData) {
objectStore.add($scope.indexData[i]);
}
}
I am getting the following error saying: Uncaught DataError: Failed to execute 'add' on 'IDBObjectStore': The object store uses out-of-line keys and has no key generator and the key parameter was not provided.
You are specifying a keypath which instruct the store to use in-line keys. your code maybe like this:
var db;
var request = window.indexedDB.open("newDatabase", 1);
request.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore = db.createObjectStore("customers",{keyPath: "isbn"});
for (var i in $scope.indexData) {
objectStore.add({i:$scope.indexData[i], isbn:i});
}
}
Assume I have one backbone model with state
var myModel = new Backbone.Model(
{
key1:'value1',
key2:'value2',
key3:'value3'
});
myModel.on('all', function allHanlder () {
console.log(arguments);
})
I need remove key1 and key2 and change key3. Possible options are
unset key1 and key2 , set key3 attribute
clear model and set key3
option 1 results in 3 change, 3 change attribute events
myModel.unset('key1');
myModel.unset('key2');
myModel.set({key3:'newValue3'})
//events
["change:key1", Object { cid="c1355", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change", Object { cid="c1355", attributes={...}, _changing=true, more...}, Object { unset=true}]
["change:key2", Object { cid="c1355", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change", Object { cid="c1355", attributes={...}, _changing=true, more...}, Object { unset=true}]
["change:key3", Object { cid="c1355", attributes={...}, _changing=true, more...}, "newValue3", Object {}]
["change", Object { cid="c1355", attributes={...}, _changing=true, more...}, Object {}]
option 2 will result in 2 change change:attribute events
myModel.clear()
myModel.set({key3:'newValue3'})
//output
["change:key1", Object { cid="c1356", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change:key2", Object { cid="c1356", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change:key3", Object { cid="c1356", attributes={...}, _changing=true, more...}, undefined, Object { unset=true}]
["change", Object { cid="c1356", attributes={...}, _changing=true, more...}, Object { unset=true}]
["change:key3", Object { cid="c1356", attributes={...}, _changing=true, more...}, "newValue3", Object {}]
["change", Object { cid="c1356", attributes={...}, _changing=true, more...}, Object {}]
change:attribute events are fair, but I need to minimise change triggers. Something like below.
myModel.someMagicSet({key3:'newValue3'})
//output
["change:key1", Object { cid="c1355", attributes={...}, _changing=true, more...}, undefined, Object {}]
["change:key2", Object { cid="c1355", attributes={...}, _changing=true, more...}, undefined, Object {}]
["change:key3", Object { cid="c1355", attributes={...}, _changing=true, more...}, "newValue3", Object {}]
["change", Object { cid="c1355", attributes={...}, _changing=true, more...}, Object {}]
Is there is a way I can achieve it without overriding backbone behaviours?
myModel.unset('key1', {silent: true});
myModel.unset('key2', {silent: true});
myModel.set({key3:'newValue3'}, {removed: ['key1', 'key2']});
This will do what you want while only triggering one change event. You are passing in the removed items to your handler in the options object. In your handler, your code should look like this:
myModel.on('all', function allHandler (model, options) {
console.log(options.removed); // this should show you what has been removed before
// other code
})
Alternately, you could pass a flag in your options with each event which you could analyze in your handler, which would determine whether the handler was run or not. This would give your handler access to what has been changed, but it would have to store it outside of it's own scope in order to access it the next time.
myModel.unset('key1', {finished: false});
myModel.unset('key2', {finished: false});
myModel.set({key3:'newValue3'}, {finished: true});
EDIT: Here is a one liner that should do everything:
myModel.clear({reset: {key3: 'newValue3'}});
and then in your handler do this
myModel.on('all', function allHandler (model, options) {
if (options.reset){
model.set(options.reset);
}
// other code
})
The thing you should watch out for is that clear removes the id too, so if you need that you should pass it in with your options:
myModel.clear({reset: {key3: 'newValue3', id: myModel.get('id')}});
Below is what i am populating my collection with (FacetModels)
How do I access the AvailableValues[] array
"FacetModels":[
{
"FacetDisplayLabel":null,
"SelectedValues":[],
"AvailableValues":[],
"UnknownResults":0,
"ActionURI":null,
"FacetGroupName":"Category",
"FacetGroupFriendlyId":"SourceCategory",
"FacetGroupOrder":10,
"AllowSuggestions":false
},
This is my view, as you will see all i have access to is the array of FacetModels, I need to be able to pass FacetModels[0].AvailableValues.Name so I can display each category Name
CategoryListItemView = Backbone.View.extend({
tagName: "li",
className: "category",
initialize: function (options) {
this.template = _.template( $("#categorylist_template").html());
},
render: function () {
var category = this.model
console.log(category);
console.log(this.model.toJSON());
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
});
Display from console
a.Model {cid: "c2", attributes: Object, collection: r, _changing: false, _previousAttributes: Object…}
_changing: false
_events: Object
_pending: false
_previousAttributes: Object
attributes: Object
ActionURI: null
AllowSuggestions: false
AvailableValues: Array[8]
0: Object
ActionURI: "/api/search?firstname=thomas&firstname_variants=true&lastname=smith®ion=all&sourcecategory=armed%20forces%20utf0026%20conflict"
Count: 8943
DisplayLabel: "Armed Forces & Conflict"
IsUnknown: false
Name: "Armed Forces & Conflict"
proto: Object
1: Object
2: Object
3: Object
4: Object
5: Object
6: Object
7: Object
length: 8
proto: Array[0]
FacetDisplayLabel: null
FacetGroupFriendlyId: "SourceCategory"
FacetGroupName: "Category"
FacetGroupOrder: 10
SelectedValues: Array[0]
UnknownResults: 0
proto: Object
changed: Object
cid: "c2"
collection: r
proto: Object
Inside your view the javascript array is available through this.model.get('AvailableValues'). If you need Available values to be a Backbone Collection, you can override parse to populate the AvailableValues property with a collection instead of an array.
There are some other SO questions that have examples of this:
backbone-js-fetching-a-more-complex-data-and-using-as-a-collection
how-to-override-backbones-parse-function