How to use geo location within filter polygon using typesense instantsearch adapter - geolocation

I create one demo instantsearch js with typesense.
Issue is when i search city the result come all result not filtering with _geoloc and polygon.
I use _geoloc field to store lat long with float array in typesense.
{"name": "_geoloc", "type": "float[]" , "facet": true },
And _geoloc pass geoLocationField parameter in Typesense instantSearch adapter.
const polygon = [
42.01,-124.31,
48.835509470063045,-124.40453125000005,
45.01082951668149,-65.95726562500005,
31.247243545293433,-81.06578125000004,
25.924152577235226,-97.68234374999997,
32.300311895879545,-117.54828125
];
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
server: {
apiKey: "xyz",
nodes: [{
host: "localhost",
port: "8108",
protocol: "http",
}, ],
cacheSearchResultsForSeconds: 2 * 60,
},
insidePolygon: [polygon],
geoLocationField: "_geoloc",
additionalSearchParameters: {
queryBy: "name",
},
});

As of v2.1.0 of the Typesense Instantsearch adapter, you can use the configure InstantSearch.js widget for this, instead of passing it into the Typesense adapter.
Something like this:
const polygon = [
42.01,-124.31,
48.835509470063045,-124.40453125000005,
45.01082951668149,-65.95726562500005,
31.247243545293433,-81.06578125000004,
25.924152577235226,-97.68234374999997,
32.300311895879545,-117.54828125
];
instantsearch.widgets.configure({
insidePolygon: polygon,
});

Thank you for helping #ErJab
After some research, I got a new solution and it's working perfectly.
Typesense adapter updated their code for the polygon search.
https://github.com/typesense/typesense-instantsearch-adapter/blob/978af9577ef632003aa2de6b1761772d979377eb/src/SearchRequestAdapter.js#L167-L198
now we can able to search inside a polygon.
const polygon = [
42.01,-124.31,
48.835509470063045,-124.40453125000005,
45.01082951668149,-65.95726562500005,
31.247243545293433,-81.06578125000004,
25.924152577235226,-97.68234374999997,
32.300311895879545,-117.54828125
];
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
server: {
apiKey: "xyz",
nodes: [{
host: "localhost",
port: "8108",
protocol: "http",
}, ],
cacheSearchResultsForSeconds: 2 * 60,
},
geoLocationField: "_geoloc",
additionalSearchParameters: {
queryBy: "name",
},
});
const searchClient = typesenseInstantsearchAdapter.searchClient;
const search = instantsearch({
searchClient,
indexName: "airports",
});
search.addWidgets([
searchBox({
container: '#searchbox',
placeholder: 'Search for products',
}),
configure({
insidePolygon : polygon,
}),
]);

Related

Vercel and Nextjs: redirect subdomain to path dynamically

I have a nextjs project with a :client param which represents a client, like this:
domain.com/:client
And I have multiple clients... so I need to do this rewrite:
:client.domain.com -> domain.com/:client
For example for clients:
google.domain.com -> domain.com/google
netflix.domain.com -> domain.com/netflix
...
Inside the same project.
Any way to do that?
You can use the redirects option in the vercel.json, as Maxime mentioned.
However, it requires 1 extra key.
For example, if your app is available at company.com:
{
...
redirects: [
{
"source": "/",
"has": [
{
"type": "host",
"value": "app.company.com"
}
],
"destination": "/app"
}
]
}
More info:
Example Guide
vercel.json docs
Create a config in your project root with next.config.js
If this file exists add the following snippet to it, Mind you, we used example.com in place of domain .com as Body cannot contain "http://domain. com" in stackoverflow
// next.config.js
module.exports = {
async redirects() {
return [
{
source: "/:path*",
has: [
{
type: "host",
value: "client.example.com",
},
],
destination: "http://example.com/client/:path*",
permanent: false,
},
];
},
};
To confirm it's also working in development, try with localhost
module.exports = {
reactStrictMode: true,
// async rewrites() {
async redirects() {
return [
{
source: "/:path*",
has: [
{
type: "host",
value: "client.localhost",
},
],
destination: "http://localhost:3000/client/:path*",
permanent: false,
},
];
},
};
Dynamic Redirect
To make it dynamic, we'll create an array of subdomains
const subdomains = ["google", "netflix"];
module.exports = {
async redirects() {
return [
...subdomains.map((subdomain) => ({
source: "/:path*",
has: [
{
type: "host",
value: `${subdomain}.example.com`,
},
],
destination: `https://example.com/${subdomain}/:path*`,
permanent: false,
})),
];
},
}
You can read more from the official next.js doc redirects or rewrite

"Client network socket disconnected before secure TLS connection was established" - Neo4j/GraphQL

Starting up NestJS & GraphQL using yarn start:dev using await app.listen(3200);. When trying to connect to my Neo4J Desktop, I get this error trying to get my queries at localhost:3200/graphQL:
"errors": [
{
"message": "Client network socket disconnected before secure TLS connection was established",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"getMovies"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"code": "ServiceUnavailable",
"name": "Neo4jError"
}
}
}
],
"data": null
}
So I figured my local Neo4J desktop graph is not running correctly, but I can't seem to find any answer how to solve it.. Currently I have a config.ts file which has:
export const HOSTNAME = 'localhost';
export const NEO4J_USER = 'neo4j';
export const NEO4J_PASSWORD = '123';
and a file neogql.resolver.ts:
import {
Resolver,
Query,
Args,
ResolveProperty,
Parent,
} from '#nestjs/graphql';
import { HOSTNAME, NEO4J_USER, NEO4J_PASSWORD } from '../config';
import { Movie } from '../graphql';
import { Connection, relation, node } from 'cypher-query-builder';
import { NotFoundException } from '#nestjs/common';
const db = new Connection(`bolt://${HOSTNAME}`, {
username: NEO4J_USER,
password: NEO4J_PASSWORD,
});
#Resolver('Movie')
export class NeogqlResolver {
#Query()
async getMovies(): Promise<Movie> {
const movies = (await db
.matchNode('movies', 'Movie')
.return([
{
movies: [{ id: 'id', title: 'title', year: 'year' }],
},
])
.run()) as any;
return movies;
}
#Query('movie')
async getMovieById(
#Args('id')
id: string,
): Promise<any> {
const movie = (await db
.matchNode('movie', 'Movie')
.where({ 'movie.id': id })
.return([
{
movie: [{ id: 'id', title: 'title', year: 'year' }],
},
])
.run<any>()) as any;
if (movie.length === 0) {
throw new NotFoundException(
`Movie id '${id}' does not exist in database `,
);
}
return movie[0];
}
#ResolveProperty()
async actors(#Parent() movie: any) {
const { id } = movie;
return (await db
.match([node('actors', 'Actor'), relation('in'), node('movie', 'Movie')])
.where({ 'movie.id': id })
.return([
{
actors: [
{
id: 'id',
name: 'name',
born: 'born',
},
],
},
])
.run()) as any;
}
}
Be sure to pass the Config object like this:
var hostname = this.configService.get<string>('NEO4J_URL');
var username = this.configService.get<string>('NEO4J_USERNAME');
var password = this.configService.get<string>('NEO4J_PASSWORD');
db = new Connection(`${hostname}`, {
username: username,
password: password,
}, {
driverConfig: { encrypted: "ENCRYPTION_OFF" }
});
I had the same problem with grandSTACK when running against a neo4j version 4 server. According to Will Lyon this is due to mismatched encryption defaults between driver and database: https://community.neo4j.com/t/migrating-an-old-grandstack-project-to-neo4j-4/16911/2
So passing a config object with
{ encrypted: "ENCRYPTION_OFF"}
to the Connection constructor should do the trick.

how to hide columns of antd data table for small devices(mobile view)?

If the table has five columns i want to display only 2 columns for mobile view
https://ant.design/components/table
you can keep columns in component state and dynamically filter the columns on window resize. Something like this
useEffect(() => {
window.addEventListener("resize", <callback function to update columns>);
// cleanup
return() => window.removeEventListener("resize");
});
Inside render method you need to declare columns with let and change them if window.innerWidth < 480 (I made it less then 500 px to be safe). By changing, I mean filtering from an array of columns only those columns that you want. The best way to filter is by key, because it's unique. This is how the code looks in react:
import React, { PureComponent } from "react";
import { Table } from "antd";
export default class MainPage extends PureComponent {
renderMobileTable = columns => {
return columns.filter(
column => column.key === "name" || column.key === "city"
);
};
render() {
const dataSource = [
{
key: "1",
name: "Mike",
lastName: "Willins",
age: 32,
address: "10 Downing Street",
city: "Chicago"
},
{
key: "2",
name: "John",
lastName: "Billards",
age: 42,
address: "5th Blvd",
city: "New York"
}
];
let columns = [
{
title: "Name",
dataIndex: "name",
key: "name"
},
{
title: "Last Name",
dataIndex: "lastName",
key: "lastName"
},
{
title: "Age",
dataIndex: "age",
key: "age"
},
{
title: "Address",
dataIndex: "address",
key: "address"
},
{
title: "City",
dataIndex: "city",
key: "city"
}
];
const isMobile = window.innerWidth < 500;
if (isMobile) {
columns = this.renderMobileTable(columns);
}
return <Table dataSource={dataSource} columns={columns} />;
}
}
For the source code you may refer to my repository on GitHub.
NOTE: if you are testing mobile view in Chrome Dev Tools, make sure you reload the page after resizing, as we put the logic into render method and the application has to be re-rendered or reloaded.
In antd v4 you can use column prop 'responsive'
const columns = [{
title: 'identification number',
dataIndex: 'ID',
responsive: ['sm'],
}]
https://ant.design/components/table/#Column

Telegram (simplest) inline bot send photo 2 times on iOS

I have an inline bot similar to #pic and it works ok, when I type query word I can see pictures appear so I can choose one and send to a chat. The problem is when I do - 2 copies of same result are sent. This happens only on iOS client. On Android, PC and other platforms only one picture is being sent. I have checked all logs (the bot is done in Node.js) and for every request I have a single response. It seems to be a iOS client bug, although #pic bot works fine. Has someone encountered this bug or have an idea of what can cause it?
Example of answerInlineQuery response object
{
"inline_query_id": "817150058382989968",
"results": [
{
"type": "photo",
"id": "se090",
"photo_url": "http://www.shadowera.com/secardbot361/se090.jpg",
"thumb_url": "http://www.shadowera.com/secardbot361/se090.jpg",
"photo_width": 344,
"photo_height": 480,
"title": "Tracking Gear",
"description": "You can view the hands of opposing players.",
"caption": "king"
},
{...
UPDATE:
So I have created a simplest possible inline bot in node.js #iosinlinebot (you can try it) AND you have the same exact behaviour: only on iOS devices you will send 2 images to the chat once tapped on the result.
Here is the code:
exports.handler = function(event, context) {
console.log(event);
const https = require("https");
let answer = {
inline_query_id: event.inline_query.id,
results: [{
type: "photo",
id: "abcd",
photo_url: "https://lh3.googleusercontent.com/jVXglyWWL5J2y1vRN-7Jy3_ozvvZc4w5486IAkbAIrWcNN_vn7YuIvhc1JDtGq43BqGl=s180",
thumb_url: "https://lh3.googleusercontent.com/jVXglyWWL5J2y1vRN-7Jy3_ozvvZc4w5486IAkbAIrWcNN_vn7YuIvhc1JDtGq43BqGl=s180",
photo_width: 180,
photo_height: 180,
title: "title",
description: "description",
caption: "test"
}],
cache_time:1
};
let postBody = JSON.stringify(answer);
let options = {
hostname: "api.telegram.org",
port: 443,
path: "/bot" + process.env.TOKEN + "/answerInlineQuery",
method: "POST",
headers: {
'Content-Type': 'application/json',
'Content-Length': postBody.length
}
};
let postreq = https.request(options, (res) => {
res.setEncoding('utf8');
const body = [];
res.on('data', (chunk) => body.push(chunk));
res.on('end', () => {
let j = body.join('');
console.log(j);
//context.done(JSON.parse(j));
});
});
postreq.write(postBody);
postreq.end();
};
this is an event object (coming from telegram):
{
"update_id": 12345678,
"inline_query": {
"id": "123456789123456789",
"from": {
"id": 123456789,
"is_bot": false,
"first_name": "Firstname",
"username": "username",
"language_code": "it-IT"
},
"query": "test",
"offset": ""
}
}
UPDATE:
Thanks to Sedric Heidarizarei we were able to find the problem. It is a telegram iOS client bug. If InlineQueryResultPhoto object contains caption field, you user will post 2 images to the chat.
It is very important to close the Begin and the End of your regex with ^ and $.
For example a user with this regex /^[/]start/ can use start and start a and start b as Bot command And will allow Them to receive your photo, But with /^[/]start$/, The user must enter the exact /start Command.
1: Use This Module: node-telegram-bot-api
2: And Send Your Photo:
bot.onText(/^[/]start$/, (msg) => {
const opts = {
parse_mode: 'Markdown',
reply_markup: {
inline_keyboard: [[{
text: '🔙',
callback_data: 'back'
}]]
}
};
bot.sendPhoto(msg.chat.id, 'AgADBAADn64xBoABCx8L8trMV9eMqgDAAEC', opts); // Your Photo id
});
Notice:
Open an empty project and just use and check your InlineQueryResultPhoto.
update:
That is a Telegram bug for For temporary use, remove caption from your let answer ={}

Google Linecharts json data source?

I use google line chart but I cant success to assing source to chart.
script
<script type="text/javascript">
// Load the Visualization API and the piechart package.
google.load('visualization', '1', { 'packages': ['corechart'] });
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
function drawChart() {
var jsonData = $.ajax({
url: '#Url.Action("AylikOkumalar", "Enerji")',
dataType: "json",
async: false
}).responseText;
var rows = new google.visualization.DataTable(jsonData);
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'T1');
data.addColumn('number', 'T2');
data.addColumn('number', 'T3');
data.addRows(rows);
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.LineChart(document.getElementById('chart_div')).draw(data, { curveType: "function",
width: 700, height: 400,
vAxis: { maxValue: 10 }
}
);
}
</script>
action
public ActionResult AylikOkumalar()
{
IEnumerable<TblSayacOkumalari> sayac_okumalari = entity.TblSayacOkumalari;
var sonuc = sayac_okumalari.Select(x => new
{
okuma_tarihi = ((DateTime)x.okuma_tarihi).ToShortDateString(),
T1 = (int)x.toplam_kullanim_T1,
T2 = (int)x.toplam_kullanim_T2,
T3 = (int)x.toplam_kullanim_T3
});
return Json(sonuc, JsonRequestBehavior.AllowGet);
}
json output
and script error:
Argument given to addRows must be either a number or an array.
I use it first time. So I dont know what should I do. How can use charts with mvc 3. there is no example enough.
Thanks.
data.addRows(rows);
'rows' should be an array - something like :
data.addRows([
[new Date(1977,2,28)], 1, 2, 3],
[new Date(1977,2,28)], 1, 2, 3]
]);
or your jsonData could be instead the whole structure :
{
"cols": [
{"id": "", "label": "Date", "type": "date"},
{"id": "", "label": "T1", "type": "number"}
],
"rows": [
{"c":[{"v": "Apr 24th"}, {"v": 56000} ]},
{"c":[{"v": "May 3rd" }, {"v": 68000} ]}
]
}

Resources