elasticsearch Multisearch request with aggregations - javascript

When I perform a single search request with aggregations it works fine. But when I try to perform a multisearch request, aggregations don't seem to work. Isn't it supposed to?
Below is my code, am I doing something wrong (the output is list of hits and no aggregations)? or is msearch not support aggs?
var body = {
"query": {
"filtered" : {
"filter" : {
"and" : filterObj.filters
}
}
}
};
var bodyArray = [];
for (var aggItem in multiaggregations){
bodyArray.push({ "index" : "myindex", "size" : 0});
bodyArray.push({ "query": body.query, "aggregations": aggItem});
}
client.msearch({
body: bodyArray
});

Related

Include if..else... statement in JS forEach method?

While trying to update a dictionary inside the iterator I got the error "SyntaxError: expected expression, got keyword 'if'"
The ut_frequencies data looks like:
{ "_id" : "app1", "cnt" : 3422 }
{ "_id" : "app2", "cnt" : 2752 }
{ "_id" : "app3", "cnt" : 2736 }
{ "_id" : "app4", "cnt" : 2711 }
Which I suppose is a list of dictionaries. I want to check if the app is already in the data dictionary and if so, update the "utf" value, if not, then add a new item only with the "utf" attribute set.
ut_frequencies.forEach(item=>
if(item._id in data){
data[item._id]["utf"] = item.cnt;
}else{
data[item._id] = {utf: item.cnt, atf: 0, ptf: 0};
}
)
Which is the best way to solve this.
The problem is that on the right of the arrow, an expression is expected.
An if condition is not an expression, therefore you should put braces around the body of the function.
ut_frequencies.forEach(item => {
if(item._id in data){
data[item._id]["utf"] = item.cnt;
}else{
data[item._id] = {utf: item.cnt, atf: 0, ptf: 0};
}
});

Meteor: Return only single object in nested array within collection

I'm attempting to filter returned data sets with Meteor's find().fetch() to contain just a single object, it doesn't appear very useful if I query for a single subdocument but instead I receive several, some not even containing any of the matched terms.
I have a simple mixed data collection that looks like this:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"items" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06"),
"slug" : "this-is-a-long-slug",
"title" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6"),
"slug" : "mc",
"title" : "Technology"
}
]
}
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e8"),
"name" : "Sitewide",
"items" : [
{
"_id" : ObjectId("57a38bc75ac9e2efc0fa09c9"),
"slug" : "example",
"name" : "Single Example"
}
]
}
I can easily query for a specific object in the nested items array with the MongoDB shell as this:
db.categories.find( { "items.slug": "mc" }, { "items.$": 1 } );
This returns good data, it contains just the single object I want to work with:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"items" : [
{
"_id" : ObjectId("57a38b985ac9e2efc0fa09c8")
"slug" : "mc",
"name" : "Single Example"
}
]
}
However, if a similar query within Meteor is directly attempted:
/* server/publications.js */
Meteor.publish('categories.all', function () {
return Categories.find({}, { sort: { position: 1 } });
});
/* imports/ui/page.js */
Template.page.onCreated(function () {
this.subscribe('categories.all');
});
Template.page.helpers({
items: function () {
var item = Categories.find(
{ "items.slug": "mc" },
{ "items.$": 1 } )
.fetch();
console.log('item: %o', item);
}
});
The outcome isn't ideal as it returns the entire matched block, as well as every object in the nested items array:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"boards" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06")
"slug" : "this-is-a-long-slug",
"name" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6")
"slug" : "mc",
"name" : "Technology"
}
]
}
I can then of course filter the returned cursor even further with a for loop to get just the needed object, but this seems unscalable and terribly inefficient while dealing with larger data sets.
I can't grasp why Meteor's find returns a completely different set of data than MongoDB's shell find, the only reasonable explanation is both function signatures are different.
Should I break up my nested collections into smaller collections and take a more relational database approach (i.e. store references to ObjectIDs) and query data from collection-to-collection, or is there a more powerful means available to efficiently filter large data sets into single objects that contain just the matched objects as demonstrated above?
The client side implementation of Mongo used by Meteor is called minimongo. It currently only implements a subset of available Mongo functionality. Minimongo does not currently support $ based projections. From the Field Specifiers section of the Meteor API:
Field operators such as $ and $elemMatch are not available on the client side yet.
This is one of the reasons why you're getting different results between the client and the Mongo shell. The closest you can get with your original query is the result you'll get by changing "items.$" to "items":
Categories.find(
{ "items.slug": "mc" },
{ "items": 1 }
).fetch();
This query still isn't quite right though. Minimongo expects your second find parameter to be one of the allowed option parameters outlined in the docs. To filter fields for example, you have to do something like:
Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items": 1
}
}
).fetch();
On the client side (with Minimongo) you'll then need to filter the result further yourself.
There is another way of doing this though. If you run your Mongo query on the server, you won't be using Minimongo, which means projections are supported. As a quick example, try the following:
/server/main.js
const filteredCategories = Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items.$": 1
}
}
).fetch();
console.log(filteredCategories);
The projection will work, and the logged results will match the results you see when using the Mongo console directly. Instead of running your Categories.find on the client side, you could instead create a Meteor Method that calls your Categories.find on the server, and returns the results back to the client.

Applying JSON.parse() to unusual JSON file

Trying to access the value field of this JSON file using JSON.parse() in Meteor, but I cannot get it to return anything. I suspect there is an error in my syntax in selecting the data from the imported JS object.
{"status":"success","data":{"subjects":[{"value":"ABC","descr":"Descriptions"}]},"message":null,"meta":{"copyright":"Copyright","referenceDttm":"Date"}}
I'm trying to store it into an array, subjectArray. This is the code I'm using:
var subjectArray = new Array();
subjectFile = HTTP.get("https://classes.cornell.edu/api/2.0/config/subjects.json?roster=FA15");
subjectJSON = JSON.parse(subjectFile);
for (int i=0; i<subjectJSON.length; i++) {
subjectArray.push(subjectJSON[i].value)
}
Pretty printed this is:
{
"data": {
"subjects": [
{
"descr": "Descriptions",
"value": "ABC"
}
]
},
"message": null,
"meta": {
"copyright": "Copyright",
"referenceDttm": "Date"
},
"status": "success"
}
Responses from HTTP calls can take a while to come back so you should read your replies in an async way. You should move all of your code related to the "get" inside a callback function. If you want to find out more about HTTP and callbacks in Meteor make sure you check the docs
If you know what "value" is in your for loop ('cause I don't), then this is your answer:
HTTP.get("https://classes.cornell.edu/api/2.0/config/subjects.json?roster=FA15", function (err, res) {
if(!!err) return false;
subjectJSON = JSON.parse(res);
for (var i = 0; i < subjectJSON.length; i++) {
subjectArray.push(subjectJSON[i].value);
}
return true;
});
Also, there is no int in JavaScript.

backbone-relational .set() method not updating related models

I've got backbone-relational working fairly well so far. I have relationships and reverse relationships well established (see below). When I initially call .fetch() on my Country model instance, the nominees array is parsed out into nominee models perfectly.
When I call .fetch() again later, however, these related models do not update, even though the nominee data has changed (e.g. the vote count has incremented). Essentially it seems that Backbone's .set() method understands relationships initially but not subsequently.
Country Model
var Country = Backbone.RelationalModel.extend({
baseUrl : config.service.url + '/country',
url : function () {
return this.baseUrl;
},
relations : [
{
type : Backbone.HasMany,
key : 'nominees',
relatedModel : Nominee,
collectionType : Nominee_Collection,
reverseRelation : {
key : 'country',
includeInJSON : false
}
}
]
});
JSON Response on country.fetch()
{
"entrant_count" : 1234,
"vote_count" : 1234,
"nominees" : [
{
"id" : 3,
"name" : "John Doe",
"vote_count" : 1,
"user_can_vote" : true
},
{
"id" : 4,
"name" : "Marty McFly",
"vote_count" : 2,
"user_can_vote" : true
}
]
}
Any help would be greatly appreciated, as always.
So it appears that backbone-relational specifically forgoes updating relations automatically (see the updateRelations method), and simply emits a relational:change:nominees event which your models can target. If, however, you wish to programmatically update your related models, simply modify the updateRelations method as follows:
Backbone.RelationalModel.prototype.updateRelations = function( options ) {
if ( this._isInitialized && !this.isLocked() ) {
_.each( this._relations || [], function( rel ) {
// Update from data in `rel.keySource` if set, or `rel.key` otherwise
var val = this.attributes[ rel.keySource ] || this.attributes[ rel.key ];
if ( rel.related !== val ) {
this.trigger( 'relational:change:' + rel.key, this, val, options || {} );
// automatically update related models
_.each(val, function (data) {
var model = rel.related.get(data.id);
if (model) {
model.set(data);
} else {
rel.related.add(data);
}
});
}
}, this );
}
};
(Note that this does not handle deletion of models from a collection, only updates to existing models, and the addition of new models to a collection)

Updating MongoDB

Does anyone know how I can update in MongoDB.
I want to update the totalVisits with timesvisted
// Test data
var currentUser = "John"
var currentPage = "pageName"
var timesvisited = 59
Page.find({"_id" : currentUser}, [], {},function(err, pages) {
pages = pages.map(function(ud) {
return { userDetails: ud};
});
//database structure example
{ "_id" : "John",
"pageName" : { "totalVisits" : 58,
"timeOnPage" : 2432,
"lastVisitDate" : "10/11/2011",
"clickNoOnPage" : "5"
},
"anotherPageName" : { "totalVisits" : 18,
"timeOnPage" : 5362,
"lastVisitDate" : "01/10/2011",
"clickNoOnPage" : "15"
I am trying to update the totalVisits value and have tried something like
{$set : { pages[0].userDetails[currentPage].totalVisits : timesvisted}}
However I get a "SyntaxError: Unexpected token [" message
One of the problems I am having is with the [currentPage] section as currentPage can change so I can not hard code the pageName in.
Edit ***
I have modified this line
lastVisitedSiteDate = {$set : { "pageName.totalVisits" : timesvist}};
and this works fine. However, I need the pageName not to be hard coded in, its needs to be something like currentPage so different page names can be passed into it e.g. anotherPageName.
The second parameter to Mongo's find function specifies which fields to pull back. It needs to be a document, as in {}, not an array.

Categories