Restrict suggestions in Algolia to postcode - filtering

In Algolia Places I want to restrict the suggestions for streets to a specific postcode. I cannot seem to get it to work however. I thought this might be how it's done, but it doesn't work.
const optionsStreet = {
appId: '...',
apiKey: '...',
container: document.querySelector('#address'),
templates: {
value: function (suggestion) {
return suggestion.name;
}
}
};
const configStreet = {
language: 'de', // Receives results in German
postcodes: ['12345'],
type: 'address'
};
const placesStreet = places(optionsStreet).configure(configStreet);
placesStreet.on('change', function resultSelected(e) {
document.querySelector('#address').value = e.suggestion.name || '';
});

There's no easy way to do what you want.
You might want to open a feature request!
In the meantime...
First option
If that's some data you can get, use the insidePolygon option to restrict the searches to the geographical area represented by the postcode(s) you're interested in.
Note that you can filter on multiple disjoint polygons.
That option is a bit cumbersome to put in place but will give you the best results, as it ensures you'll get only the hits from the area you want.
Second option
You can also fork the project and fiddle with that part of the code:
.then(content => {
const hits = content.hits.map((hit, hitIndex) =>
formatHit({
formatInputValue: controls.formatInputValue,
hit,
hitIndex,
query,
rawAnswer: content,
})
);
controls.onHits({
hits,
query,
rawAnswer: content,
});
return hits;
})
Filter content.hits for the hits that match your postcode only and you'll get your filtered suggestions.
Two recommendations:
Increase the hitsPerPage setting because you're going to be removing many results from the hits due to your postcode filter:
const placesStreet = places(options).configure({
...config,
computeQueryParams(query) {
return {...query, hitsPerPage: 100};
}
});
You'll want to fine-tune the 100 depending on what you need.
Use the arountLatLng configuration to specify a point within the postcode area you want to target, to maximize the number of hits with the correct postcode.

Related

How can I apply conditional filtering to MongoDB documents?

I am having a really hard time figuring out how to apply multiple levels of filtering to my mongoDB documents (not sure if this phrasing is correct).
I am trying to create an app that will allow users to perform a search and retrieve only those documents that match the filters they have chosen to apply. A user might chose to apply only one filter or combine multiple filters.
For example, the user might be looking for a house. The available filters could be location, size and type. If the user applies the location filter with a value of ‘London’, they should get only those houses available in London. If they choose to combine the above location with the type filter with a value of ‘2-bedroom-apartment’, they should get all 2-bedroom apartments available in London.
How can I make sure that the results are conditionally filtered, depending on the filters that the user has applied?
I think I am supposed to use $match, but I don’t understand if I can use multiple queries with it.
What I have come up with so far is the following:
const getFilteredData = async(req, res) => {
try {
const { filter1, filter2, filter3 } = req.query;
const filteredData = await dataModel.aggregate([
{$match:{
$and:[{filter1:filter1},{filter2: filter2}, {filter3:filter3}] //1st option: all of the filters are applied by the user
}}
])
res.status(201).json({data: filteredData});
}
catch(err) {
res.status(404).json({message: err.message});
}
}
With the above code, the results are filtered only when all 3 filters are being applied. How can I cater to different combinations of filters being applied by the user (only one filter, filter1 & filter3 combined etc)?
Any help will be massively appreciated.
Assuming req.query can be {name: "Coat", city: "Athens"} You can do something like:
const getFilteredData = async(req, res) => {
try {
const filtersArr = [];
for (const filterKey of ['name', 'city', 'category']) {
if (req.query[filterKey]) {
const thisFilter = {};
thisFilter[filterKey] = req.query[filterKey];
filtersArr.push(thisFilter);
}
}
console.log(filtersArr)
const filteredData = await filteredDataModel.aggregate([
{$match:{
$and: filtersArr //1st option: all of the filters are applied by the user
}}
])
res.status(201).json({data: filteredData});
}
catch(err) {
res.status(404).json({message: err.message});
}
}
You can also use the original req.query like this:
const filteredData = await filteredDataModel.find(req.query)
But iterating using the code allows you to validate the keys that you want...

How to filter an array of object in Mui DataGrid?

I recently changed my tables to Mui-datagrid on Material UI 5, and I have a special use case with an array of objects. I want to enable the phone number filter in this column, but the number is provided as an object list.
phone: [
{ type: "home", number: "795-946-1806" },
{ type: "mobile", number: "850-781-8104" }
]
I was expecting a 'customFilterAndSearch' or an option to customise how to search in this specific field.
customFilterAndSearch: (term, rowData) =>
!!rowData?.suppressedOptions.find(({ description }) =>
description?.toLowerCase().includes(term.toLowerCase())
),
I have made some tries with the filterOperators, but no success yet. I have made a full example here https://codesandbox.io/s/mui-data-grid-vs05fr?file=/demo.js
As far as I can see from the DataGrid documentation I don't see any way to change the filter function for a specific function.
Likely the best workaround for your use case will be converting this to a string be converting the data to a string before you pass it to the datagrid. Though you will lose the styling that you currently do by making the phone type bold.
On second though your best best would probably be to split the phone column into two columns which would probably be the cleanest way of solving your problem
Add helper function.
You could potentially add a helper function to just map all the phone lists to something like mobilePhone or homePhone
const mapPhoneObject = (rows) => {
rows.forEach((row) => {
row.phone.forEach((phone) => {
row[`${phone.type}Phone`] = phone.number;
});
});
return rows
};
I've added a fork of your snippet with my function, it is I think the most viable solution for your problem: https://codesandbox.io/s/mui-data-grid-forked-ppii8y

how to cancel stop loss and take profit order when position close on binance futures with rest api

I'm using Binance futures rest API for algorithmic trading. after creating a buy or sell order, I'm also creating "take profit" and "stop-loss" orders, when I look at the Binance app. it looks like regular SL/TP orders but when I close positions manually, or when any SL/TP orders executed SL/TP orders still waiting in my open orders.
But when I create SL/TP orders with the Binance app and close position (for any reason) open orders also close for the same symbol.
Here is the endpoint and parameters for creating SL/TP orders;
https://fapi.binance.com/fapi/v1/order?symbol=ETHUSDT&side=BUY&type=TAKE_PROFIT_MARKET&timestamp=12123123&closePosition=true&stopPrice=4100&workingType=MARK_PRICE&priceProtect=true
this one create a TP order for the ETHUSDT symbol but I don't know why that order doesn't cancel when the position closed.
is there any missing parameter for creating SL/TP orders?
I'm have a related issue. For your specific problem what I have noticed is that when you submit, for example, a market long position. You can follow up with a TP and SL order by setting them as TAKE_PROFIT_MARKET and STOP_MARKET respectively.
For this to work you must by in 'one-way' mode (as opposed to 'hedge' mode).
Then set the value of 'timeInForce' to 'GTE_GTC' - I couldnt see this value in the documentation but I did see that when you set an order via the UI with a TP/SL this is what is shown. Also set 'reduceOnly' to True.
Then when you close the original market order both these 'pending' orders will be removed.
Just tested that you can in fact submit all these orders in a batch (list of json) to:
POST /fapi/v1/batchOrders
batch_payload = [
{
'newClientOrderId': '467fba09-a286-43c3-a79a-32efec4be80e',
'symbol': 'ETHUSDT',
'type': 'MARKET',
'quantity': '9.059',
'side': 'SELL'
},
{
'newClientOrderId': '6925e0cb-2d86-42af-875c-877da7b5fda5',
'symbol': 'ETHUSDT',
'type': 'STOP_MARKET',
'quantity': '9.059',
'side': 'BUY',
'stopPrice': '3037.9',
'timeInForce': 'GTE_GTC',
'reduceOnly': 'True'
},
{
'newClientOrderId': '121637a9-e15a-4f44-b62d-d424fb4870e0',
'symbol': 'ETHUSDT',
'type': 'TAKE_PROFIT_MARKET',
'quantity': '9.059',
'side': 'BUY',
'stopPrice': '2748.58',
'timeInForce': 'GTE_GTC',
'reduceOnly': 'True'
}
]
By default Binance doesn't close the TAKE_PROFIT_MARKET or STOP_MARKET after position is closed.. you need to manually close those orders, you can pull the current opened orders and filter them based on the positionSide (SELL / LONG / BOTH) and origType (TAKE_PROFIT_MARKET / STOP_MARKET) and you can get the orderId for those orders and batch cancel them or cancel them one by one
const position = 'LONG' // LONG, SHORT, BOTH
axios
.get('https://fapi.binance.com/fapi/v1/openOrders', {
params: {
symbol: 'BTCUSDT'
}
})
.then(({ data }) => {
const orderIds = data
.filter(
({ positionSide, origType }) =>
positionSide === position &&
['TAKE_PROFIT_MARKET', 'STOP_MARKET'].includes(origType)
)
.map(({ orderId }) => orderId)
// Use batch cancel or cancel order one by one
console.log('orderIds', orderIds)
})

vue js 2 - for loop in multiple rest calls fetchData

I am trying to get wp-rest and Vuejs 2 to work together, so far things are coming along nicely apart from this one rest call that requires another request for the design to be complete. Essentially I want to be able to iterate / loop through the first request and dynamically change update the second request.
And my second question is performance, overall the rest calls are taking a bit longer to load - is there something I can do to optimize?
Context:
The first result data gives me an id, slug and title to all the posts I want to display only on the homepage as featured - through that id or slug I want to pass it to the second request - so I can pull in more information about those posts - like featured image and other meta field data.
<pre>export default {
name: 'work',
data () {
return {
loading: false,
page: null,
pagesingle: null,
error: null
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
this.$http.get('/cms/wp-json/wp/v2/pages/?slug=work&_embed')
.then(result => {
this.page = result.data
this.$http.get('/cms/wp-json/wp/v2/cases-studes/?slug=case-study-name').then(
result => this.pagesingle = result.data
);
})
}
}
}</pre>
I think you want to look at Promise.all. It will take an array of promises, wait for them all to complete, and then resolve with an array of results.
You would build your array of promises based on the array of slugs and ids in your first request. Maybe something like
const promises = result.data.articles.map((article) =>
this.$http.get(`/cms/wp-json/wp/v2/cases-studies/?slug=${encodeURIComponent(article.slug)}`)
);
Getting the results is as easy as
Promise.all(promises).then((results) => {
this.arrayOfSinglePages = results.map((result) => result.data);
});
Now your this.page has the array of id (and stuff) and this.arrayOfSinglePages has the page details for each of them in the same order.

algolia how to orderby string-value and geolocation

I am working on a prototype for a new product, need some help to figure out algolia feasibility. I did go through their documentation but couldn't find right answer. Any help appreciated.
Best example of our data is classified. In dataset we have geolocation(lat-lng) and category
[
{
category: 'retail_shops',
"_geoloc": {
"lat": 40.639751,
"lng": -73.778925
},
title: 'walget1'
},
{
category: 'retail_shops',
"_geoloc": {
"lat": 40.639751,
"lng": -73.778925
},
title: 'walget1'
},
]
Search Requirement
sortby category, selected category first, then all other in anyorder
sortby geolocation, this is secondary filter
We need to display all data in the system but selected category first and distance as secondary.
I am trying to do this is javascript, did find find search and searchForFacetValues methods but documentation is all-around. Any ideal how to achieve this? don't need code but general guidance will definitely help.
In order to do so, you can use a multiple-queries strategy, where you would have a query with a filter that matches the category, and then another query that matches all objects not in the category. In the query parameters you can then use the aroundLatLng field or the aroundLatLngViaIp field.
The following snippet should help you get a better understanding of how to achieve what you want:
const client = algoliasearch('ApplicationID', 'apiKey');
// these two values would be obtained from somewhere (like InstantSearch)
const query = 'walg';
const category = 'retail_shops';
const queries = [{
indexName: 'products',
query: `${query}`,
params: {
hitsPerPage: 3,
filters: `category:${category}`,
aroundLatLngViaIP:true
}
}, {
indexName: 'products',
query: `${query}`,
params: {
hitsPerPage: 10,
filters: `NOT category:${category}`,
aroundLatLngViaIP:true
}
}];
const searchCallback = (err, content) => {
if (err) {
console.error(err);
return;
}
const categorySpecificResults = content.results[0];
for (var i = 0; i < categorySpecificResults.hits.length; ++i) {
console.log(categorySpecificResults.hits[i]);
}
const geolocatedOnlyResults = content.results[1];
for (var i = 0; i < geolocatedOnlyResults.hits.length; ++i) {
console.log(geolocatedOnlyResults.hits[i]);
}
}
// perform the 2 queries in a single API call:
// - 1st query targets index `products` with category filter and geolocation
// - 2nd query targets index `products` with negative category filter and geolocation
client.search(queries, searchCallback);
You will find more information about how to use multiple queries on this page:
How to use multiple Queries
If you want a more fine grained control on the geolocation, like for instance defining a precision or a maximum range for the search, you can find more about these different features on these pages:
aroundLatLng: used when you want to define the geographical center of your query
aroundRadius: used to limit a search to a certain range around the center of the query
aroundPrecision: defines how precise the ranking has to be when it comes to distance.