Server.ts 4.62 KiB
import cookieParser from 'cookie-parser'
import morgan from 'morgan'
import path from 'path'
import helmet from 'helmet'
import cors from 'cors'
import express, { NextFunction, Request, Response } from 'express'
import StatusCodes from 'http-status-codes'
import 'express-async-errors'
import BaseRouter from './routes'
import logger from '@shared/Logger'
import { MongoClient } from 'mongodb'
import { chain } from 'stream-chain'
import * as fs from 'fs'
import { parser } from 'stream-json'
import { streamArray } from 'stream-json/streamers/StreamArray'
import { IBikeTrip } from '@entities/BikeTrip'
/************************************************************************************
 *                              Fill database and open connection
 ***********************************************************************************/
export const dbName = 'bikesharing'
const url = `mongodb://localhost:27017/${dbName}`
export const dbClient = new MongoClient(url, { useNewUrlParser: true, useUnifiedTopology: true })
export const bikeTripsCollectionName = 'biketrips';
(async () => {
    try {
        console.log("Attempting to connect to MongoDB server.")
        await dbClient.connect()
        console.log("Connected to MongoDB server.")
        const db = dbClient.db(dbName)
        const bikeTripCollection = await db.collection(bikeTripsCollectionName)
        const stats = await bikeTripCollection.stats()
        if(stats.count === 0){
            // create ascending index on fields startDate and endDate
            bikeTripCollection.createIndex({ startDate : 1 })
            bikeTripCollection.createIndex({ endDate : 1 })
            const dataStreamFromFile = fs.createReadStream('src/shared/data/bike-sharing-trip-data-4-january-28-february-reduced.json')
            const pipeline = chain([
                dataStreamFromFile,
                parser(),
                streamArray(),
            let bikeTripsTemp: IBikeTrip[] = []
            const startTime = Date.now()
            console.log('Inserting bike trips into database, please wait...')
            pipeline.on('data', async bikeTripsChunk => {
                bikeTripsTemp.push(bikeTripsChunk.value)
                if(bikeTripsTemp.length === 50000){
                    dataStreamFromFile.pause()
                    await bikeTripCollection.insertMany(bikeTripsTemp)
                    bikeTripsTemp = []
                    console.log(`...${(await bikeTripCollection.stats()).count} documents in database...`)
                    dataStreamFromFile.resume()
}) pipeline.on('end', async () => { await bikeTripCollection.insertMany(bikeTripsTemp) const bikeTripCollectionStats = await bikeTripCollection.stats() console.log(`Database inserts done! Added ${bikeTripCollectionStats.count} bike trip documents to database, in ${(Date.now() - startTime)/1000} seconds.`) }) } else { console.log(`Found ${stats.count} bike trip documents in database`) } } catch (err) { console.log(err.stack) } })() /************************************************************************************ * Set basic express settings ***********************************************************************************/ const app = express() const { BAD_REQUEST } = StatusCodes app.use(express.json()) app.use(express.urlencoded({extended: true})) app.use(cookieParser()) // Show routes called in console during development if (process.env.NODE_ENV === 'development') { app.use(morgan('dev')) } // Allow cors // eslint-disable-next-line @typescript-eslint/no-unsafe-call app.use(cors()) // Security if (process.env.NODE_ENV === 'production') { app.use(helmet()) } // Add APIs app.use('/api', BaseRouter) // Print API errors // eslint-disable-next-line @typescript-eslint/no-unused-vars app.use((err: Error, req: Request, res: Response, next: NextFunction) => { logger.err(err, true) return res.status(BAD_REQUEST).json({ error: err.message, }) }) /************************************************************************************ * Serve front-end content ***********************************************************************************/ const dir = path.join(__dirname, 'frontend-build') app.set('views', dir) // middleware is needed to make express serve static CSS and Javascript files app.use(express.static(dir)) app.get('/*', (req: Request, res: Response) => { res.sendFile('index.html', {root: dir}) })
// Export express instance export default app