JSON GTFS TIMETABLE - javascript

What i want to do is get timetable from GTFS for specific bus. (Specific lane number) by node-gtfs.
My code looks like this:
const config = JSON.parse(
await readFile(new URL("./config.json", import.meta.url))
);
import { importGtfs } from "gtfs";
import { readFile, writeFile } from "fs/promises";
import { openDb } from "gtfs";
const db = await openDb(config);
try {
await importGtfs(config);
} catch (error) {
console.error(error);
}
import { getStoptimes } from "gtfs";
// Get all stoptimes
const trips = await getStoptimes();
//fs write file trips.json
await writeFile(
new URL("./trips.json", import.meta.url),
JSON.stringify(trips)
);
I'm trying to get just the timetable for specific bus lane, but i'm reciving some garbage and not even ONE timetable, i'm almost sure that i need to use more than one of those functions. No idea which, and how. (I also want to store it to the JSON File)
Also I was looking for some GTFS "tutorials" how to use it, how can i fetch data using node-gtfs but there is a really really small amount of them, almost none.
I've tried https://gtfstohtml.com/
It returns table for every BUS Lane in the HTML Table.
That is something similar that i want to do, add to that expandable list with the full timetable:
https://transit-arrivals-widget.blinktag.com/?stop_id=40585
Thanks !

Related

Request columns for multiple tables using supabasejs

So supabase allows for two tables pretty simply.
const { data, error } = await supabase
.from('table1')
.select('table1.thing1, table1.thing2, table2(table2.thing2, table2.thing3)')
.console.log(data)
What I am trying to do is access a 3rd table to get information from table2 but I need table 1 to have the data.
const { data, error } = await supabase
.from('table1')
.select('table1.thing1, table2.thing2, table2(table2.thing2, table2.thing3), table3(table3.thing2, table3.thing2)')
console.log(data)
I would expect this to give me a data across all 3 but I just get a null returned.
With #supabase if you want to connect more than one table via supabasejs query your best bet is to just make a view. I hope this helps someone else out there!

How to use Apify web scrapper data in a React.js interface?

I'm using Apify web scraper to scrape h1,h2 and a span from a website. I have read all of their docs but I can't seem to find an answer for this.
async function pageFunction(context) {
const $ = context.jQuery;
const h1 = $('main h1').first().text();
const first_h2 = $('h2').first().text();
const random_text_from_the_page = $('main span').text();
// Print some information to actor log
context.log.info(`URL: ${context.request.url}, What is going on?: ${h1}`);
// Manually add a new page to the queue for scraping.
// await context.enqueueRequest({ url: 'http://www.example.com' });
// Return an object with the data extracted from the page.
// It will be stored to the resulting dataset.
return {
url: context.request.url,
h1,
first_h2,
random_text_from_the_page
};
}
How can I use that json data I get back and display it in a simple React UI for people to see?
Is it even possible? If not in React maybe just a simple vanilla JS UI?
Thank you.

Atomic update of data structure in Firebase Realtime Database

I am using typescript and the Firebase Realtime Database (cannot use Firestore), and I have data in the form on an interface MyData as follows:
enum RunStatus {
RUNNING,
ENDED
}
interface IResults {
firstItem: string;
secondItem: number;
}
interface MyData {
status: RunStatus;
results: IResults;
}
Suppose I have 10 clients that might end up writing this data simultaneously to (1) change status from RUNNING to ENDED and (2) set the results field.
What I want is for only the first client to be able to do this, so I need to use a transaction of some sort.
My data is stored at this path: "/some/path/here/mydata".
As near as I can tell from the limited documentation, my writes should look something like this:
class MyDatabase {
db: Database;
constructor(db_: Database) {
this.db = db_
}
writeMyData(newData: MyData) {
const path="/some/path/here/mydata";
const reference=child(ref(this.db),path);
runTransaction(reference, (currentData) => {
if (currentData) {
if (currentData.status!=RunStatus.ENDED && newData.status==RunStatus.ENDED) {
currentData.status=newData.status;
currentData.results=newData.results;
// Or, I could have just set currentData=newData
}
}
return currentData;
});
}
}
Is this correct? And what exactly does it do if multiple clients try to run this at the same time? The documentation says something about runTransaction being automatically rerun if currentData is updated by another client while the first client is writing. Can someone please explain to me if this is correct, and what is happening here?

How to read and write to local JSON files from React.js?

I have looked at multiple resources for this, however, none seem to be able to answer my question. I have a local JSON file in my React app called items.json. In that file, is a list of objects, which I want to be able to update. I have tried using fs however this apparently doesn't work in React, as I received this error:
Unhandled Rejection (TypeError): fs.readFileSync is not a function
What I am trying to do, is that when the code gets a new item, it looks through the JSON file to see if there is an existing object with a matching values in its name property. If there is, it increments that objects count property by 1, otherwise it creates a new object, and appends it to the list in the JSON file. This is the code that I have written to do that. The logic seems sound (although its not tested) but I can't figure out how to read/write the data.
let raw = fs.readFileSync("../database/items.json");
let itemList = JSON.parse(raw);
let found = false;
for (let item of itemList.averages) {
if (item.name === this.state.data.item_name) {
found = true;
item.count += 1;
}
}
if (!found) {
let newItem = {
name: this.state.data.item_name,
count: 1,
}
itemList.averages.push(newItem);
}
let newRaw = JSON.stringify(itemList);
fs.writeFileSync("../database/items.json", newRaw);
The JSON file:
{
"averages": [
{
"name": "Example",
"count": 1,
}
]
}
First of all, the browser itself doesn't have access to the filesystem, so you won't be able to achieve that using your react app. However, this can be achieved if you use Node.js(or any other FW) at the backend and create an API endpoint which can help you to write to the filesystem.
Secondly, if you wanted to only do things on the frontend side without creating an extra API just for saving the data in a JSON file which I think is not necessary in your case. You can use localstorage to save the data and ask the user to download a text file using this :
TextFile = () => {
const element = document.createElement("a");
const textFile = new Blob([[JSON.stringify('pass data from localStorage')], {type: 'text/plain'}); //pass data from localStorage API to blob
element.href = URL.createObjectURL(textFile);
element.download = "userFile.txt";
document.body.appendChild(element);
element.click();
}
Now, To use local storage API you can check here - https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
reading and writing JSON file to local storage is quite simple with NodeJs, which means a tiny piece of backend API in express would help get this job done.
few piece of code that might help you. Assuming you JSON structure would be such as below;
{
"name":"arif",
"surname":"shariati"
}
Read JSON file;
// import * as fs from 'fs';
const fs = require('fs')
fs.readFile('./myFile.json', 'utf8', (err, jsonString) => {
if (err) {
return;
}
try {
const customer = JSON.parse(jsonString);
} catch(err) {
console.log('Error parsing JSON string:', err);
}
})
customer contains your JSON, and values can be accessed by customer.name;
Write to JSON File
Let's say you have an update on your JSON object such as below;
const updatedJSON = {
"name":"arif updated",
"surname":"shariati updated"
}
Now you can write to your file. If file does not exist, it will create one. If already exists, it will overwrite.
fs.writeFile('./myFile.json', JSON.stringify(updatedJSON), (err) => {
if (err) console.log('Error writing file:', err);
})
Importing and reading from json can be like:
import data from ‘./data/data.json’;
then use .map() to iterate data.
for writing locally you can use some libraries like https://www.npmjs.com/package/write-json-file

TypeORM AfterSave() triggers after creation but when queried, it returns NULL

I have an Entity called Trip. The structure is:
What I want is whenever a new trip is created, the room column should be populated with ${tripId}_${someRandomStringHere}. So for example, I just created a new trip using this body:
The response should be:
The newly created trip has the id of 15. So, the response has the room valued at 15_4gupvdo0ea408c25ia0qsbh because again: ${tripId}_${someRandomStringHere}.
This is working as expected whenever I POST the request and create the trip. BUT whenever I query all the trips created, the room property of each trip objects shows null!
Look at the /api/trips:
room property is NULL. So what the heck I dont understand what is happening.
My Trip Entity code is:
import { PrimaryGeneratedColumn, Column, CreateDateColumn,
UpdateDateColumn, Entity, Unique, ManyToOne, AfterInsert, JoinColumn, getConnection } from 'typeorm'
import { DriverEntity } from 'src/driver/driver.entity';
#Entity('trips')
export class TripEntity {
#PrimaryGeneratedColumn()
id: number
#Column()
destination: string
#Column('decimal')
destination_lat: number
#Column('decimal')
destination_long: number
#Column()
maxPassenger: number
#Column()
totalPassenger: number
#Column({ nullable: true })
room: string
#CreateDateColumn()
created_at: Date
#UpdateDateColumn()
updated_at: Date
// --------->HERE: The after insert
#AfterInsert()
async createSocketRoom(): Promise<void> {
const randomString = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
this.room = `${this.id}_${randomString}`
}
// Trip belongs to driver
// Adds driver_id to trips table
#ManyToOne(type => DriverEntity, driver => driver.trips)
#JoinColumn({ name: 'driver_id' })
driver: DriverEntity
}
My Trip Service Code is:
async create(data: CreateTripDTO) {
const { driver_id } = data
const driver = await this.driverRepository.findOne({ where: { id: driver_id } })
const trip = await this.tripRepository.create(data)
trip.driver = driver
await this.tripRepository.save(trip)
return trip
}
I dont think I need to include the Trip Controller code but anyway..
I don't know why it is happening because I have my User Entity with #BeforeUpdate and works fine...
After reading alot of similar github issues, watched youtube tutorials [Hi Ben Awad! :D], I found a somewhat fix.. by using Subscribers
Actually, I don't know what is the difference of the Listener/Subscriber. Maybe I am doing the wrong usage. Can someone enlighten me please? For example the difference of AfterSave of Entity Listener vs AfterSave of Entity Subscriber. When/Best case to use? something like that. Anyway back with the "fix..."
I created a Trip Subscriber:
import { EventSubscriber, EntitySubscriberInterface, InsertEvent } from "typeorm";
import { TripEntity } from "src/trip/trip.entity";
#EventSubscriber()
export class TripSubsriber implements EntitySubscriberInterface<TripEntity> {
// Denotes that this subscriber only listens to Trip Entity
listenTo() {
return TripEntity
}
// Called after entity insertion
async afterInsert(event: InsertEvent<any>) {
console.log(`AFTER ENTITY INSERTED: `, event.entity);
const randomString = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
// query the trip with given event.entity
const trip = await event.manager.getRepository(TripEntity).findOne(event.entity.id)
// populate the room with desired format
trip.room = `${trip.id}_${randomString}`
// save it!
await event.manager.getRepository(TripEntity).save(trip)
}
}
At first it is not working but after digging for hours again, I need to add a subscriber property with the value of the path of my subscribers at the ormconfig.json for it to work!
e.g: "subscribers": [
"src/subscriber/*.ts"
]
Again, the Trip Subscriber code seems spaghetti to me because I already have the event.entity object but I do not know how to update it without the need of querying and updating it using event.manager.getRepository(). Please can someone fix this code for me? the proper way of doing it?
NOW, It is working!
the request body:
the /api/trips res:
My questions are:
Why whenever I use that method methoud subscriber, it is not working. Is it not the proper way to do it? The why is it in the docs? Or for other use case?
Do I really have to use subscriber for it to achieve? Thats so many steps.
I came from Rails. So having to create files/subscribers just to do it somewhat tiring. Unlike ActiveRecord's after_save callback it is very easy..
PS. I'm new to nest-js and typeorm
#AfterInsert method will just modify your JS object after inserting into DB is done. So thats reason why is your code not working. You have to use #BeforeInsert decorator. BeforeInsert will modify your JS entity/object before inserting/saving into DB.
What it looks like is happening with your AfterInsert is that you are creating the random room string just fine, but you are not saving the value to the database, only using the return of the id so that you can create the string. What you could do in your AfterInsert is run the save() function from the EntityManager or RepositoryManger once more and commit the value to the database, similar to what you have happening in you Subscriber. I haven't dived too deep into the Subscriber/Listener vs Before-/AfterInsert decorators, so I can't give a deeper answer to your questions.
If you'd rather not make two commits to the database, you can always do a query for the most recent id and increment it by 1 (thus, matching what the new objects id should be) with something like
const maxId = await this.tripRepository.findOne({select: ['id'], order: {id: "DESC"} });
const trip = await this.tripRepository.create(data);
const randomString = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
this.room = `${maxId + 1}_${randomString}`
trip.driver = driver
await this.tripRepository.save(trip)
It's a little clunky to look at, but it doesn't require two writes to the database (though you'll definitely need to ensure that after creation room and trip have the same id).
Your last option would be to create a Trigger in your database that does the same thing as your JavaScript code.
You just use "this.save()" after all in createSocketRoom() function
https://i.stack.imgur.com/oUY8n.png my query after use that!!!

Categories

Resources