Mongoosastic: error sorting by distance - elasticsearch

I am getting the following Elastic Search error when I try to sort search results by distance with Mongoosastic:
{ message: 'SearchPhaseExecutionException[Failed to execute phase
[query_fetch], all shards failed; shardFailures
{[rQFD7Be9QbWIfTqTkrTL7A][users][0]: SearchParseException[[users][0]:
query[filtered(+keywords:cafe)->GeoDistanceFilter(location,
SLOPPY_ARC, 25000.0, -70.0264952, 41.2708115)],from[-1],size[-1]:
Parse Failure [Failed to parse source
[{"timeout":60000,"sort":[{"[object Object]":{}}]}]]]; nested:
SearchParseException[[users][0]:
query[filtered(+keywords:cafe)->GeoDistanceFilter(location,
SLOPPY_ARC, 25000.0, -70.0264952, 41.2708115)],from[-1],size[-1]:
Parse Failure [No mapping found for [[object Object]] in order to sort
on]]; }]' }
See bellow for code sample:
var query = {
"filtered": {
"query": {
"bool": {
"must": [
{
"term": {
"keywords": "cafe"
}
}
]
}
},
"filter": {
"geo_distance": {
"distance": "25km",
"location": [
41.2708115,
-70.0264952
]
}
}
}
};
var opts = {
"sort": [
{
"_geo_distance": {
"location": [
41.2708115,
-70.0264952
],
"order": "asc",
"unit": "km",
"distance_type": "plane"
}
}
],
"script_fields": {
"distance": "doc[\u0027location\u0027].distanceInMiles(41.2708115, -70.0264952)"
}
};
User.search(query, opts, function (err, data) {
if (err || !data || !data.hits || !data.hits.hits || !data.hits.hits.length) {
return callback(err);
}
var total = data.hits.total,
//page = params.page || 1,
per_page = query.size,
from = query.from,
//to = from +
page = query.from / query.size,
rows = data.hits.hits || [];
for (var i = 0; i < rows.length; i++) {
rows[i].rowsTotal = total;
}
callback(err, toUser(rows, params));
});
Here is the User schema:
var schema = new Schema({
name: {type: String, default: '', index: true, es_type: 'string', es_indexed: true},
location: {type: [Number], es_type: 'geo_point', es_indexed: true, index: true},
shareLocation: {type: Boolean, default: false, es_type: 'boolean', es_indexed: true},
lastLocationSharedAt: {type: Date},
email: {type: String, default: '', index: true, es_type: 'string', es_indexed: true},
birthday: {type: String, default: ''},
first_name: {type: String, default: ''},
last_name: {type: String, default: ''},
gender: {type: String, default: ''},
website: {type: String, default: '', index: true, es_indexed: true},
verified: {type: Boolean, default: false},
});

I am also getting an error, I think the upgrade of Mongoosastic is double wrapping the code. It def seems to be based on 'sort' rather than on search but still reviewing. Val seems to have a better idea of what is going on as perhaps it has something to do with user schema rather than function.
I am using a similar schema and just upgraded and encountered issues.

Related

How to create custom resolvers for Gatsby page queries?

I have a Gatsby application pulling data from Sanity.
This is Sanity's schema for the course.js:
import video from './video'
export default {
// Computer name
name: `courses`,
// Visible title
title: `Courses`,
type: `document`,
fields: [
{
name: `title`,
title: `Course title`,
type: `string`,
description: `Name of the course`
},
{
name: `slug`,
title: `slug`,
type: `slug`,
options: {
source: `title`,
maxLength: 100,
}
},
{
name: `price`,
title: `Price`,
type: `number`
},
{
name: `thumbnail`,
title: `Thumbnail`,
type: `image`,
options: {
hotspot: true,
}
},
{
name: `playlist`,
title: `Playlist`,
type: `array`,
of: [
{
title: `Video`,
name: `video`,
type: `video`,
}
]
},
]
}
And this is Sanity's schema for video.js:
export default {
// Computer name
name: `video`,
// Visible title
title: `Video`,
type: `object`,
fields: [
{ name: `title`, type: `string`, title: `Video title` },
{ name: `url`, type: `url`, title: `URL` },
{ name: `public`, title: `public`, type: `boolean`, initialValue: false }
]
}
This Gatsby page query:
{
allSanityCourses {
nodes {
title
price
playlist {
url
title
public
}
}
}
}
Results in:
{
"data": {
"allSanityCourses": {
"nodes": [
{
"title": "Master VS Code",
"price": 149,
"playlist": [
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Introduction",
"public": true
},
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Philosophy",
"public": false
},
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Tech and Tools",
"public": false
},
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Integration",
"public": true
},
{
"url": "https://www.youtube.com/watch?v=PRz1Nv9GUzs",
"title": "Extensions",
"public": false
}
]
}
]
}
},
"extensions": {}
}
To prevent the url field from being injected into the React component this Gatsby page query runs on (because these urls are paid for), I need to remove it, if the public field is set to false.
I've tried inserting this into gastby-node.js:
exports.createSchemaCustomization = ({ actions, schema }) => {
const { createTypes } = actions
const typeDefs = [
schema.buildObjectType({
name: "SanityCourses",
fields: {
playlist: {
type: "[SanityVideo]",
url: {
type: "String",
resolve: (source) => "nope"
},
},
},
interfaces: ["Node"],
}),
]
createTypes(typeDefs)
}
And:
exports.createResolvers = ({ createResolvers }) => {
const resolvers = {
SanityCourses: {
playlist: {
type: "[SanityVideo]",
url: {
type: "String",
resolve(source, args, context, info) {
return "nope"
},
}
},
},
}
createResolvers(resolvers)
}
But neither seems to work. The url field returns the url as always. The resolvers don't even seem to fire (I've tried putting console.log()'s in them).
Any help on how to remove the url field if the public field is set to false, or general direction to go in would be very appreciated.
Ditch the attempt in createSchemaCustomization since you don't need to customize the schema here (though I believe there is a way to achieve what you want using it, it is not expected that the data in it is sourced from existing nodes, and this undeclared dependency can create caching issues).
Then update your createResolvers function to something like this:
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
SanityVideo: {
safeUrl: {
type: "String",
resolve: (source, args, context, info) => source.public ? source.url : null
},
},
})
}
I don't believe resolvers can replace schema-originated nodes (fields), hence using safeUrl instead of url
The type you are adding a field to is SanityVideo, and it doesn't matter what the parent node is—this will apply to all instances of SanityVideo in your data

Nested type without referencing another schema in Mongoosastic

I want to give a nested field the elastic mapping type "nested" by using Mongoosastic. I also want to specify the es_type of the fields in the nested field.
My schema looks like this:
const CarOwner = new Schema({
cars: [{
name: {
type: String,
es_indexed: true,
},
price: {
type: Number,
es_indexed: true,
es_type: 'float'
},
}],
});
I want this ElasticSearch mapping:
{
"mappings": {
"carowner": {
"properties": {
"cars": {
"type": "nested",
"properties": {
"name": { "type": "text" },
"price": { "type": "float" },
}
}
}
}
}
}
The only Mongoosastic examples I've found looks like this:
var Car = new Schema({
name: {
type: String,
es_indexed: true,
},
price: {
type: Number,
es_indexed: true,
es_type: 'float'
},
})
var CarOwner = new Schema({
cars: {
type:[Car],
es_indexed: true,
es_type: 'nested',
es_include_in_parent: true
}
})
Do I have to create a subschema or is there any way I could use Mongoosastic to create the mapping I want?

ExtJS: How to hide specific data on store with filtering?

I want to hide a record on Grid that returns from server.
I've setted a filter on store and can reach that specific data but how I'll handle to hide/ignore this record?
fooStore: {
....
filters: [
function(item) {
let me = this;
let theRecord = item.data.status === MyApp.STATUS; //true
if (theRecord) {
console.log(theRecord); //True
console.log("So filter is here!!")
//How to hide/ignore/avoid to load this specific data record to load Grid??
}
}
]
},
Returned JSON;
{
"success": true,
"msg": "OK",
"count": 3,
"data": [
{
//Filter achives to this record and aim to hide this one; avoid to load this record.
"id": 102913410,
"status": "P"
},
{
"id": 98713410,
"status": "I"
},
{
"id": 563423410,
"status": "A"
}
]
}
I can't save my fiddle cause i don't have sencha forum's account so i give you my code :
Ext.application({
name : 'Fiddle',
launch : function() {
var model = Ext.create('Ext.data.Model', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'int'},
{name: 'status', type: 'string'},
]
});
var store = Ext.create('Ext.data.Store', {
autoLoad: true,
model: model,
proxy: {
type: 'ajax',
url: 'data.json',
reader: {
type: 'json',
rootProperty: 'data'
}
},
filters: [function(item) {
if (item.data.status === "P") {
return true;
}
else {
return false;
}
}],
listeners: {
load: {
fn: function() {
console.log(this.getRange());
}
}
}
});
}
});
Also i create data.json like this :
{
"success": true,
"msg": "OK",
"count": 3,
"data": [{
"id": 102913410,
"status": "P"
}, {
"id": 98713410,
"status": "I"
}, {
"id": 563423410,
"status": "A"
}]
}
I thinks it's near to you'r code and after the loading of the store the filter work as you can this :
Here is sencha fiddle link : https://fiddle.sencha.com/#view/editor
If this can't work, i don't understand what the fuck doing...

Mongoose model configuration for elasticsearch

I'm having an issue with mongoosastic in combination with KeystoneJS. I want to search for all the posts of a specific user with a match on the title. I have the following model:
var keystone = require('keystone'),
Types = keystone.Field.Types,
mongoosastic = require('mongoosastic');
User = keystone.list('User');
var Post = new keystone.List('Post');
Post.add({
title: {
type: String,
required: true,
es_indexed: true
},
state: {
type: Types.Select,
options: 'draft, published, archived',
default: 'draft',
es_indexed: true
},
author: {
type: Types.Relationship,
ref: 'User',
es_schema: User,
es_include_in_parent: true,
es_indexed:true
},
publishedDate: {
type: Types.Date,
index: true,
dependsOn: {
state: 'published'
}
},
content: {
extended: {
type: Types.Html,
wysiwyg: true,
height: 400,
es_indexed: true
}
},
});
Post.schema.plugin(mongoosastic, {
hosts: [
process.env.SEARCHBOX_SSL_URL
]
});
Post.defaultColumns = 'title, state|20%, author|20%, publishedDate|20%';
Post.register();
Post.model.createMapping(function(err, mapping) {
if (err) {
console.log('error creating mapping', err);
} else {
console.log('mapping created for Post');
}
});
User.schema.plugin(mongoosastic, {
populate: [
{path: 'author'}
]
});
I tried the approach of "Indexing Mongoose references" (https://github.com/mongoosastic/mongoosastic#indexing-mongoose-references) but I can't get it to work. Elasticsearch is not returning any hits.. My search query:
{
"query": {
"filtered": {
"query": { "match": { "title": "req.query.query" }},
"filter": { "term": { "author": "req.query.userId" }} // or author._id
}
}
}
Can someone provide me the correct Post model configuration & search query? Thanks!

GeoCode filter in mongoose elasticsearch

I am trying to do geo point filter in mongodb in meanjs. i have used mongoosastic modules but i am not able to perform geo point filter.
here below are the mongoose schema and controller code for filter.
Mongoose schema
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
mongoosastic = require('mongoosastic');
var BusinessSchema = new Schema({
name: {type: String, unique: 'Name already exists', trim: true, required: 'Name is required.', es_indexed: true},
searchTags: {type: [String], es_indexed: true},
alias: {type: Array, es_indexed: true},
// geoLocation: { type: [Number], /*/ [<longitude>, <latitude>]*/ index: '2d', /*/ create the geospatial index,*/ required: 'GeoLocation is required.', es_indexed:true,es_type:'geo_point'},
geo_cords: {
type: Array
},
address: {
address1: {type: String, required: 'Address is required', trim: true},
address2: String,
city: {type: String, required: 'City is required', trim: true},
// state: {type: String, required: 'State is required', trim: true},
country: {type: String, required: 'Country is required', trim: true},
postalCode: {type: String, required: 'Postal code is required', trim: true},
neighbourhood: String
},
isActive: {
type: Boolean,
default: true,
es_indexed: true
},
dateUpdated: {
type: Date
, es_indexed: true
},
dateCreated: {
type: Date,
default: Date.now
, es_indexed: true
}
});
controller code for filter and query
var mongoose = require('mongoose'),
Business = mongoose.model('Businesses');
var query = {
"query_string": {
"multi_match": {
"query": categoryIds.join(' OR '),
"fields": ["categoryIds", "relatedCategoryIds"]
}
},
"filter": {
"bool": {
"should": [
{"term": {"address.postalCode": "110016"}},
{"geo_distance": {
"distance": "50km",
"geo_cords": [-122.3050, 37.9174]
}
}
],
}
}
}
Business.search(query, function (err, results) {
// sendResponse(req, res, err, results)
if (!err) {
res.json(results);
} else {
res.status(400).send({message: 'Business Not Found'})
}
});
while doing this i am getting a long error saying
QueryParsingException[[businessess] failed to find geo_point field [geo_cords]
According to the documentation of mongoosastic
Geo mapping
Prior to index any geo mapped data (or calling the synchronize), the mapping must be manualy created with the createMapping (see above).
First, in your schema, define 'geo_cords' this way:
geo_cords: : {
geo_point: {
type: String,
es_type: 'geo_point',
es_lat_lon: true
},
lat: { type: Number },
lon: { type: Number }
}
Add an es_type: 'object' to each Array or embbeded type
alias: {type: Array, es_indexed: true, es_type: 'object'}
Then call .createMapping() on the model just after you've created it.

Resources