Elasticsearch query parse failure - angularjs

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

Related

How dynamically transform my "Object" to List in ng-model at view

I'm trying to transform my object to list dynamically, so I'm building at view instead of declaring at controller.
I don't want to declare like this: custom_fields.title_field.type_text_field = [] because the title_field is built dynamic, it could be any kind of text like full_name
My json as is:
"custom_fields":{
"title_dynamic_generate_field":{
"type_text_field":{
"name":"John",
"first_name":"Wick"
},
"type_boolean_field":{
"is_badass": true,
"is_good_movie": true
},
"type_select_field": {
"this_select": 1,
"i_got_this": "nope i didnt got this"
}
},
And to be:
"custom_fields":{
"title_dynamic_generate_field":{
"type_text_field":[{
"name":"John",
"first_name":"Wick"
}],
"type_boolean_field":[{
"is_badass": true,
"is_good_movie": true
}],
"type_select_field": [{
"this_select": 1,
"i_got_this": "nope i didnt got this"
}]
},
the object I'm trying to transform into array is type_text_field which can be dynamic too, like type_date_field or type_select_field and so on.
My ng-model is like this:
ng-model="objectApp.application.applicant.custom_fields[layout.dynamic_title][input.type][input.variable]"
the [input.type] is that I'm trying to transform into array, how can I achieve this? I tried to use $index, but got strange results.
We can do it by 2 solutions:
There is a question about your task:
? how you want handle if we have more than one type_text_field in title_dynamic_generate_field? because you want to convert it to "type_text_field":[{},...]
however my answers about the question are:
If we know what's the dynamic params which we want to send theme as json, i mean if we know what is the key of title_dynamic_generate_field or type_text_field, we do as this sample:
var data = {
"custom_fields": {
dynamicParamIs1: 'title_dynamic_generate_field',
dynamicParamIs2: 'type_text_field',
"title_dynamic_generate_field": {
"type_text_field": {
"name": "John",
"first_name": "Wick"
}
}
}
}
var paramHelper1 = json.custom_fields[json.custom_fields.dynamicParamIs1];
var paramHelper2 = json.custom_fields.dynamicParamIs2;
var solutionA = function (object, as) {
var array = [];
for (var key in object) {
var newObject = object[key];
array.push(newObject);
}
object[as] = array;
}
solutionA(paramHelper1, paramHelper2);
We changed a model of our json which can help us to detect (find) the keys
If we don't know what is the dynamic params are, we do as this:
var data = {
"custom_fields": {
"title_dynamic_generate_field": {
"type_text_field": {
"name": "John",
"first_name": "Wick"
}
}
}
}
var solutionB = function (json) {
var array = [];
for (var key in json) {
var j1 = json[key];
for (var key2 in j1) {
var j2 = j1[key2];
for (var key3 in j2) {
var fullObject = j2[key3];
array.push(fullObject);
j2[key3] = array;
}
}
}
}
solutionB(data);
This sample is manual which we use nested for to detect the keys name

Mongoose doesn't create subdocument from JSON array

I'm trying to write a JSON object that contains both first-level data along with arrays into MongoDB.
What happens instead is all first-level data is stored, but anything contained in an array isn't. When logging the data the server receives, I see the entire object, which leads me to believe there's something wrong with my Mongoose code.
So for example if I send something like this:
issueId: "test1",
issueTitle: "testtest",
rows: [
{order:1,data: [object]},
{order:2,data: [object]},
]
Only the following gets stored:
issueId: "test1",
issueTitle: "testtest",
lastUpdated: Date,
I have the following model for Mongo:
//model.js
var mongoose = require('mongoose');
var model = mongoose.Schema({
issueId : String,
issueTitle : String,
lastUpdated : {type: Date, default : Date.now},
rows : [{
order : Number,
data : [
{
title : String,
text : String,
link : String,
}
]
}]
});
module.exports = mongoose.model('Model', model);
And the routing code, where I believe the problem likely is:
//routes.js
const mongoose = require('mongoose');
const Model = require('./model.js');
...
app.post('/api/data/update', function(req, res) {
let theData = req.body.dataToInsert;
console.log(JSON.stringify(theData,null,4));
Model.findOneAndUpdate(
{issueId : theData.issueId},
{theData},
{upsert: true},
function(err,doc){
if(err) throw err;
console.log(doc);
});
});
As well, here's the part of the Angular controller storing the data. I don't think there's any problem here.
pushToServer = function() {
$http.post('/api/data/update',{
dataToInsert : $scope.dataObject,
}).then(function successCallback(res){
console.log("all good", JSON.stringify(res,null,3));
}, function errorCallback(res){
console.log("arg" + res);
});
}
Look at the first question in the mongoose FAQ:
http://mongoosejs.com/docs/faq.html
Mongoose doesn't create getters/setters for array indexes; without them mongoose never gets notified of the change and so doesn't know to persist the new value. The work-around is to use MongooseArray#set available in Mongoose >= 3.2.0.
// query the document you want to update
// set the individual indexes you want to update
// save the document
doc.array.set(3, 'changed');
doc.save();
EDIT
I think this would work to update all of the rows. I'd be interested to know if it does work.
let rowQueries = [];
theData.rows.forEach(row => {
let query = Model.findOneAndUpdate({
issueId: theData.issueId,
'row._id': row._id
}, {
$set: {
'row.$': row
}
});
rowQueries.push(query.exec());
});
Promise.all(rowQueries).then(updatedDocs => {
// updated
});

AngularJS and JSON returns undefined

Hi I have got a data in LocalStorage as JSON string:
[
{"Date":"28/04/2016","Time":"08:00","Title":"Title 1"},
{"Date":"28/04/2016","Time":"08:30","Title":"Title 2"}
]
And my module.factory looks like:
module.factory('$schedule', function() {
var schedule = {};
var result = JSON.parse(localStorage.getItem('myAgenda'));
schedule.items = [{
title: result.Title,
date: result.Date,
time: result.Time
}];
return schedule;
});
When I am trying to get data it returns undefined. When I try to get a specific object like:
console.log(result[0].Title);
It works fine and shows only the first element. I guess I missing each definition but don't know how to do it. Please help me to get all results in my schedule.items.
And I am passing the result as items into:
module.controller('ScheduleController', function($scope, $schedule) {
$scope.items = $schedule.items;
});
Many thanks.
You are trying to access fields in an array without mentioning wich array element you want to access. If you want to enumerate all agenda entries and add them to your array, it should look something like this:
module.factory('$schedule', function () {
var schedule = [];
var result = JSON.parse(localStorage.getItem('myAgenda'));
result.forEach(function (date) {
schedule.push({
title: date.Title,
date: date.Date,
time: date.Time
})
})
return schedule;
});
You should use .map over array, also add missing } in your last element of array.
var schedule = [];
//assuming result returns an array.
schedule = result.map(function(value){
return {
title: value.Title,
date: value.Date,
time: value.Time
};
})
Not familiar with module.factory, but it looks like result is an array of objects and you're accessing it like a single object when creating schedule.items.
You might have to iterate over the array and create an item per object in result.

Convert object values into array the Angular way

I have the follow object:
formData : {
_id: "550de8956e2d0948080e220f"
category: "Tag1"
isFeatured: "Yes"
likeCount: 557
title: "Integrating WordPress with Your Website"
}
I tried JavaScript but it returned a null value:
var arryFormData = Array.prototype.slice.call(formData)
How can I convert formData into an array of just its values, not properties?
As in ...
arryFormData = ["550de8956e2d0948080e220f", "Tag1", "Yes", 557, "Integrating WordPress with Your Website"]
or if You like to more functional code:
var arr = [];
angular.forEach(obj, function(value, key){
arr.push(value);
});
If you are using underscore.js,
_.values(formData)
// will get ["550de8956e2d0948080e220f", "Tag1", "Yes", 557, "Integrating WordPress with Your Website"]
See: here
Alternatively:
var res = [];
for (var x in formData){
formData.hasOwnProperty(x) && res.push(formData[x])
}
console.log(res);
In any event, the array elements might not be in the order that you want.
I prefer one line solution with Object.keys() and es6 syntax, until Object.values() is not here
const values = Object.keys(obj).map(it => obj[it])
or in es5
var values = Object.keys(obj).map(function(it) {
return obj[it]
})
I think there's No magic way, you just have to use a for loop:
for (var key in obj) {
values.push(obj[key])
}
To make it angular, you could use angular.forEach I guess...
This is how i have handled in Angular 5 to convert Object into Array as API gives response in JSON Object so we can convert it into array to use it.
let tmepArr = {};
Object.keys(res).forEach( key => {
tmepArr['name'] = [res[key].name];
tmepArr['id'] = [res[key].id];
});
this.marketplaceDropDown = [tmepArr];

Backbone.js Why is my default model present in a fetched collection?

I'm sure I'm missing something very basic. I'm setting up a collection of fetched objects
collection.fetch({reset: true})
based on a model that contains a 'defaults' property.
However, when I view the fetched collection in the console I have an extra model in it, which is set with the default attributes. Why is this happening? More importantly, how do I prevent it?
var diningApp = diningApp || {};
(function(){
"use strict";
diningApp.MenuItem = Backbone.Model.extend({
defaults: {
service_unit: null,
course: null,
formal_name: null,
meal: null,
portion_size: null,
service_unit_id: null
}
});
var MenuCollection = Backbone.Collection.extend({
model: diningApp.MenuItem,
url: '/api/dining/get_menus',
parse: function(response){
return response.menu_items;
}
});
diningApp.menuCollection = new MenuCollection();
diningApp.menuCollection.fetch({reset: true});
})();
Here is a portion of the JSON response from the server:
{
"status": "ok",
"menu_items": [
{
"service_unit": "Faculty House",
"course": "Entrees",
"formal_name": "Local CF Fried Eggs GF",
"meal": "BREAKFAST",
"portion_size": "1 Egg",
"service_unit_id": 0
},
{
"service_unit": "Faculty House",
"course": "Entrees",
"formal_name": "CageFree Scrambled Eggs GF",
"meal": "BREAKFAST",
"portion_size": "2 eggs",
"service_unit_id": 0
}]
}
And here's the resulting collection in the console:
If you dig a bit into Backone's source code to check what happens when you reset a collection, you'll end looking at Collection.set. The lines of interest to your problem are :
// Turn bare objects into model references,
// and prevent invalid models from being added.
for (i = 0, l = models.length; i < l; i++) {
attrs = models[i] || {};
// ...
This means that each falsy (false, null, etc.) item in the array is converted to an empty object before being cast into a model and receiving default values.
Either
modify your server response to remove falsy values
or alter your parse method to clean up you array
parse: function(response){
return _.compact(response.menu_items);
}

Resources