How to restrict the search of a place by the code of the country using GeoSearchControl, vuejs? - vuejs2

Good morning, I am currently working with this bookstore
https://github.com/fega/vue2-leaflet-geosearch
I have applied the rules for the places finder in the following way:
geosearchOptions: {
provider: new OpenStreetMapProvider(),
searchLabel: '¿Que direccion buscas?',
showMarker: true,
showPopup: false,
maxMarkers: 1,
style: 'bar',
retainZoomLevel : true
}
But I want you to only show me the results of certain countries with your Country Code, since at the moment I am searching for all the places, for example:
I want to restrict only one country.

To restrict search by country for OpenStreetMapProvider specify countrycodes parameter.
Per documentation:
countrycodes=<countrycode>[,<countrycode>][,<countrycode>]...
Limit search results to a specific country (or a list of countries).
<countrycode> should be the ISO 3166-1alpha2 code, e.g. gb for the
United Kingdom, de for Germany, etc.
Example
geosearchOptions: {
provider: new OpenStreetMapProvider({
params: {
countrycodes: "gb"
}
})
}

Related

FaunaDB: how to fetch a custom column

I'm just learning FaunaDB and FQL and having some trouble (mainly because I come from MySQL). I can successfully query a table (eg: users) and fetch a specific user. This user has a property users.expiry_date which is a faunadb Time() type.
What I would like to do is know if this date has expired by using the function LT(Now(), users.expiry_date), but I don't know how to create this query. Do I have to create an Index first?
So in short, just fetching one of the users documents gets me this:
{
id: 1,
username: 'test',
expiry_date: Time("2022-01-10T16:01:47.394Z")
}
But I would like to get this:
{
id: 1,
username: 'test',
expiry_date: Time("2022-01-10T16:01:47.394Z"),
has_expired: true,
}
I have this FQL query now (ignore oauthInfo):
Query(
Let(
{
oauthInfo: Select(['data'], Get(Ref(Collection('user_oauth_info'), refId))),
user: Select(['data'], Get(Select(['user_id'], Var('oauthInfo'))))
},
Merge({ oauthInfo: Var('oauthInfo') }, { user: Var('user') })
)
)
How would I do the equivalent of the mySQL query SELECT users.*, IF(users.expiry_date < NOW(), 1, 0) as is_expired FROM users in FQL?
Your use of Let and Merge show that you are thinking about FQL in a good way. These are functions that can go a long way to making your queries more organized and readable!
I will start with some notes, but they will be relevant to the final answer, so please stick with me.
The Query function
https://docs.fauna.com/fauna/current/api/fql/functions/query
First, you should not need to wrap anything in the Query function, here. Query is necessary for defining functions in FQL that will be run later, for example, in the User-Defined Function body. You will always see it as Query(Lambda(...)).
Fauna IDs
https://docs.fauna.com/fauna/current/learn/understanding/documents
Remember that Fauna assigns unique IDs for every Document for you. When I see fields named id, that is a bit of a red flag, so I want to highlight that. There are plenty of reasons that you might store some business-ID in a Document, but be sure that you need it.
Getting an ID
A Document in Fauna is shaped like:
{
ref: Ref(Collection("users"), "101"), // <-- "id" is 101
ts: 1641508095450000,
data: { /* ... */ }
}
In the JS driver you can use this id by using documentResult.ref.id (other drivers can do this in similar ways)
You can access the ID directly in FQL as well. You use the Select function.
Let(
{
user: Get(Select(['user_id'], Var('oauthInfo')))
id: Select(["ref", "id"], Var("user"))
},
Var("id")
)
More about the Select function.
https://docs.fauna.com/fauna/current/api/fql/functions/select
You are already using Select and that's the function you are looking for. It's what you use to grab any piece of an object or array.
Here's a contrived example that gets the zip code for the 3rd user in the Collection:
Let(
{
page: Paginate(Documents(Collection("user")),
},
Select(["data", 2, "data", "address", "zip"], Var("user"))
)
Bring it together
That said, your Let function is a great start. Let's break things down into smaller steps.
Let(
{
oauthInfo_ref: Ref(Collection('user_oauth_info'), refId)
oauthInfo_doc: Get(Var("oathInfoRef")),
// make sure that user_oath_info.user_id is a full Ref, not just a number
user_ref: Select(["data", "user_id"], Var("oauthInfo_doc"))
user_doc: Get(Var("user_ref")),
user_id: Select("id", Var("user_ref")),
// calculate expired
expiry_date: Select(["data", "expiry_date"], Var("user_doc")),
has_expired: LT(Now(), Var("expiry_date"))
},
// if the data does not overlap, Merge is not required.
// you can build plain objects in FQL
{
oauthInfo: Var("oauthInfo_doc"), // entire Document
user: Var("user_doc"), // entire Document
has_expired: Var("has_expired") // an extra field
}
)
Instead of returning the auth info and user as separate points if you do want to Merge them and/or add additional fields, then feel free to do that
// ...
Merge(
Select("data", Var("user_doc")), // just the data
{
user_id: Var("user_id"), // added field
has_expired: Var("has_expired") // added field
}
)
)

Find entity with most relations filtered by criteria

model Player {
id String #id
name String #unique
game Game[]
}
model Game {
id String #id
isWin Boolean
playerId String
player Player #relation(fields: [playerId], references: [id])
}
I would like to find a player with most wins. How would I do that with prisma? If there is no prisma "native" way to do it, what is the most efficient way to do this with raw SQL?
The best I could think of is:
prisma.player.findMany({
include: {
game: {
where: {
isWin: true,
},
},
},
})
But it has huge downside that you need to filter and order results in Node manually, and also store all results in memory while doing so.
Using the groupBy API you can find the player with the most wins using two queries.
1. Activate orderByAggregateGroup
You'l need to use the orderByAggregateGroup preview feature and use Prisma version 2.21.0 or later.
Update your Prisma Schema as follows
generator client {
provider = "prisma-client-js"
previewFeatures = ["orderByAggregateGroup"]
}
// ... rest of schema
2. Find playerId of most winning player
Use a groupBy query to do the following:
Group games by the playerId field.
Find the count of game records where isWin is true.
Order them in descending order by the count mentioned in 2.
Take only 1 result (since we want the player with the most wins. You can change this to get the first-n players as well).
The combined query looks like this:
const groupByResult = await prisma.game.groupBy({
by: ["playerId"],
where: {
isWin: true,
},
_count: {
isWin: true,
},
orderBy: {
_count: {
isWin: "desc",
},
},
take: 1, // change to "n" you want to find the first-n most winning players.
});
const mostWinningPlayerId = groupByResult[0].playerId;
I would suggest checking out the Group By section of the Aggregation, grouping, and summarizing article in the prisma docs, which explains how group by works and how to use it with filtering and ordering.
3. Query player data with findUnique
You can trivially find the player using a findUnique query as you have the id.
const mostWinningPlayer = await prisma.player.findUnique({
where: {
id: mostWinningPlayerId,
},
});
Optionally, if you want the first "n" most winning players, just put the appropriate number in the take condition of the first groupBy query. Then you can do a findMany with the in operator to get all the player records. If you're not sure how to do this, feel free to ask and I'll clarify with sample code.

Is there a way to use the graphLookup aggregation pipeline stage for arrays?

I am currently working on an application that uses MongoDB as the data repository. I am mainly concerned about the graphLookup query to establish links between different people, based on what flights they took. My document contains an array field, that in turn contains key value pairs. I need to establish the links based on one of the key:value pairs of that array.
I have already tried some queries of aggregation pipeline with $graphLookup as one of the stages and they have all worked fine. But now that I am trying to use it with an array, I am hitting a blank.
Below is the array field from the first document :
"movementSegments":[
{
"carrierCode":"MO269",
"departureDateTimeMillis":1550932676000,
"arrivalDateTimeMillis":1551019076000,
"departurePort":"DOH",
"arrivalPort":"LHR",
"departurePortText":"HAMAD INTERNATIONAL AIRPORT",
"arrivalPortText":"LONDON HEATHROW",
"serviceNameText":"",
"serviceKey":"BA007_1550932676000",
"departurePortLatLong":"25.273056,51.608056",
"arrivalPortLatLong":"51.4706,-0.461941",
"departureWeeklyTemporalSpatialWindow":"DOH_8",
"departureMonthlyTemporalSpatialWindow":"DOH_2",
"arrivalWeeklyTemporalSpatialWindow":"LHR_8",
"arrivalMonthlyTemporalSpatialWindow":"LHR_2"
}
]
The other document has the below field :
"movementSegments":[
{
"carrierCode":"MO269",
"departureDateTimeMillis":1548254276000,
"arrivalDateTimeMillis":1548340676000,
"departurePort":"DOH",
"arrivalPort":"LHR",
"departurePortText":"HAMAD INTERNATIONAL AIRPORT",
"arrivalPortText":"LONDON HEATHROW",
"serviceNameText":"",
"serviceKey":"BA003_1548254276000",
"departurePortLatLong":"25.273056,51.608056",
"arrivalPortLatLong":"51.4706,-0.461941",
"departureWeeklyTemporalSpatialWindow":"DOH_4",
"departureMonthlyTemporalSpatialWindow":"DOH_1",
"arrivalWeeklyTemporalSpatialWindow":"LHR_4",
"arrivalMonthlyTemporalSpatialWindow":"LHR_1"
},
{
"carrierCode":"MO270",
"departureDateTimeMillis":1548254276000,
"arrivalDateTimeMillis":1548340676000,
"departurePort":"DOH",
"arrivalPort":"LHR",
"departurePortText":"HAMAD INTERNATIONAL AIRPORT",
"arrivalPortText":"LONDON HEATHROW",
"serviceNameText":"",
"serviceKey":"BA003_1548254276000",
"departurePortLatLong":"25.273056,51.608056",
"arrivalPortLatLong":"51.4706,-0.461941",
"departureWeeklyTemporalSpatialWindow":"DOH_4",
"departureMonthlyTemporalSpatialWindow":"DOH_1",
"arrivalWeeklyTemporalSpatialWindow":"LHR_4",
"arrivalMonthlyTemporalSpatialWindow":"LHR_1"
}
]
And I am running the below query :
db.person_events.aggregate([
{ $match: { eventId: "22446688" } },
{
$graphLookup: {
from: 'person_events',
startWith: '$movementSegments.carrierCode',
connectFromField: 'carrierCode',
connectToField: 'carrierCode',
as: 'carrier_connections'
}
}
])
The above query creates an array field in the document, but there are no values in it. As per the expectation, both my documents should get linked based on the carrier number.
Just to be clear about the query, the documents contain an eventId field, and the match pipeline returns one document to me after the match stage.
Well, I don't know how I missed it, but here is the solution to my problem which gives me the required results :
db.person_events.aggregate([
{ $match: { eventId: "22446688" } },
{
$graphLookup: {
from: 'person_events',
startWith: '$movementSegments.carrierCode',
connectFromField: 'movementSegments.carrierCode',
connectToField: 'movementSegments.carrierCode',
as: 'carrier_connections'
}
}
])

Set select field options conditionally based on prior select field value

I'm using this data as an example, but in Keystone is there a way to set the options of a select field depending on a prior select field?
For example, if I have a selected a state, in the next select after it where it asks for the city, it would populate the options with the cities depending on the chosen state.
Is there a way to write an if...else statment or some way to do this without creating a bunch of city fields (oregonCities, washingtonCities, idahoCities, etc etc for all 50 states)
something like this:
state: {
type: Types.Select,
options: 'Oregon, Washington'
},
city: {
type: Types.Select,
//if state selected is oregon use these options
dependsOn: { state: 'Oregon' },
options: 'Portland, Bend, Salem'
//if state selected is washington use these options
dependsOn: { state: 'Washington' },
options: 'Seattle, Olympia, Spokane'
},
Not Possible in current version, but you can add this as feature request for next version in alpha stage. github - https://github.com/keystonejs/keystone-5

Best data-structure/db/binary-format for holding hierarchic elements

I have the following hierarchic entities:
Country, City, Street.
Every country has cities, every city has streets.
I wrote pseudo-code for what I want to run:
handle_country_before(country)
for city in country:
handle_city_before(city)
for street in city:
handle_street_before(street)
handle_street_after(street)
handle_city_after(city)
handle_country_after(country)
I tried the following approaches:
The document(noSql) approach:
I saved all my data in a flat manner:
{
country : {
# Country "x1" info corresponding with the street
},
city : {
# City "y1" info corresponding with the street
},
street : {
# street info...
}
}
{
country : {
# Country "x1" info corresponding with the street
},
city : {
# City "y1" info corresponding with the street
},
street : {
# street info...
}
}
{
country : {
# Country "x1" info corresponding with the street
},
city : {
# City "y1" info corresponding with the street
},
street : {
# street info...
}
}
{
country : {
# Country "x1" info corresponding with the street
},
city : {
# City "y2" info corresponding with the street
},
street : {
# street info...
}
}
{
country : {
# Country "x1" info corresponding with the street
},
city : {
# City "y2" info corresponding with the street
},
street : {
# street info...
}
}
Using this method, I had to use the following pseudo-code:
last_country = 0
last_city = 0
last_street = 0
for element in elements:
if element.country.id != last_country_id:
if (0 != last_country) :
handle_country_after(last_country)
handle_country_before(element.country)
if element.city.id != city:
if (0 != last_city) :
handle_country_after(last_city)
handle_country_before(element.city)
if element.street.id != street:
if (0 != last_street) :
handle_country_after(last_street)
handle_country_before(element.street)
The disadvantage: I feel like this approach is a little bit over-kill and the use of the flat structure is not fit for my case, furthermore it was very very slow and space inefficient.
The SQL approach:
I saved each entity in a table: Country, City, Street and iterated it with the following code:
country_cursor = query('select * from countries')
for country in country_cursor:
handle_country_before(country)
city_cursor = query('select * from cities where parent_country_ref=%s' % (country.id))
for city in city_cursor:
street_cursor = query('select * from streets where parent_city_ref=%s' % (city.id))
...
...
...
handle_country_after(country)
at the beginning, it looked like the best approach. But as I added more metadata tables and had to use JOIN statements it became increasingly slower, then I tried using a materialized view to speeding up things a little but got the got the same result as using documents.
The custom format approach:
I tried saving the information in my own binary-serialization format:
<number of countries>[1st-country-data]<number of citieis>[1nd-city-data]<number of streets>[1st-street-data][2nd-street-data][3rd-street...]...
the disadvantage: this couldn't scale, I couldn't update information, I couldn't fetch a particular city/street, every search was O(n).
What I am looking for is a serialization format/DB wich will be:
Able to add/update fields for existing elements
Efficient in speed, space and memory
C compliant (no CPP)
the fastest approach in your case is to use de-normalized data, create flat file/table with following information:
country city street current mayor additional information
of course data should be sorted, of course you will not use heavy to parse formats like json/xml, only pure text
then you will be able to use single loop to iterate over this array
to speed up iteration a little bit you can try to split single file into multiple ones with fixed-width rows