So erstellen Sie Ihre eigene Uber-for-X-Anwendung

In den Top Ten NodeJS-Artikeln von Mybridge ab Oktober 2016 und in den Top Ten NodeJS-Artikeln des Jahres (v.2017) enthalten

Update: Schauen Sie sich die neueste Version in meinem Tech-Blog an! Dieser Artikel ist jetzt einige Jahre alt - und aufgrund des sich schnell ändernden Ökosystems von JavaScript ist der Artikel etwas veraltet. Klicken Sie auf den obigen Link, um die aktualisierte Version dieses Artikels und des Projekts anzuzeigen.

Uber (wenn Sie noch nichts davon gehört haben) ist eine praktische App, mit der Sie ein Taxi nehmen können, ohne herumlaufen zu müssen, um nach einem zu suchen. Und vor allem löst es die Probleme von Angebot und Nachfrage, die bei Taxifahrern und Taxisuchenden bestehen.

Heute gibt es eine Vielzahl von Startups, die sich auf Uber-for-X-Apps konzentrieren. Man geht davon aus, dass Uber das, was er für Taxis getan hat, sicherlich auch für andere Angebots- / Nachfrageprobleme tun kann.

Während eines Hackathons beschlossen ich und mein Freund, eine Bürger-Cop-App zu erstellen. Wir dachten, es wäre cool, etwas zu bauen, das Ihren Freunden in schwierigen Zeiten helfen kann!

Nach einigem Nachdenken waren dies die folgenden Merkmale, auf die wir uns geeinigt haben:

  1. Zivilisten können auf Knopfdruck den nächstgelegenen Polizisten in ihrer Nachbarschaft anfordern. Es wird ein "Notsignal" auslösen und die Polizei in der Nähe alarmieren.
  2. Jede Polizei in der Nähe erhält sofort den Standort des Benutzers und kann die Anfrage annehmen und das Problem lösen.
  3. Ein Bewertungssystem
  4. Daten, die von Orten, gelösten Straftaten usw. gesammelt wurden, können auf einer Karte visualisiert oder mit einigen anderen coolen Widgets der Benutzeroberfläche grafisch dargestellt werden

In diesem Tutorial werde ich Ihnen Schritt für Schritt erklären, wie wir es erstellt haben, damit Sie Ihre eigene Uber-for-X-App erstellen können.

Bevor Sie beginnen, sollten Sie die folgenden Punkte beachten:

  • Dieses Tutorial konzentriert sich nicht darauf, wie die App für die Skalierung erstellt wird. Oder für die Leistung. Es ist im Grunde so konzipiert, dass Sie Spaß beim Erstellen haben und etwas erstellen können, das Uber nachahmt. Stellen Sie sich das so vor, als würden Sie ein Produkt mit minimaler Lebensfähigkeit erstellen, um Ihre Idee oder Ihr Startup für einen Proof-of-Concept zu demonstrieren.
  • Da ich nicht viel an Android- oder iPhone-Apps gearbeitet habe, werde ich dies so erstellen, dass es in einem Browser funktioniert.

Jetzt hat jede App, die Sie erstellen, einige wichtige Teile:

  • eine Client-App (die Sie in einem Browser oder auf den Bildschirmen Ihres Telefons sehen)
  • im Backend ein Webserver, der eingehende Anforderungen vom Client verarbeitet und Informationen weiterleitet
  • und eine Datenbank zum Speichern und Abfragen von Informationen.

Im Backend verwenden Sie MongoDB als Datenbank. Es ist einfacher zu erlernen und bietet viele Abfragetechniken für den Umgang mit Geoinformationen, die Sie für Ihre App benötigen.

Sie verwenden NodeJS für Ihre Back-End-Logik. Da es sowohl für das Front-End als auch für das Back-End dieselbe Sprache ist, müssen Sie sich keine Gedanken über das Erlernen einer neuen Sprache oder Syntax machen.

Im Frontend verwenden Sie HTML5, CSS3, JavaScript sowie die APIs für Google Maps und Orte.

Ich gehe davon aus, dass Sie bereits über gute Kenntnisse in JavaScript verfügen und zumindest theoretisch verstehen, wie NodeJS und MongoDB funktionieren.

Hier sind die Inhalte dieses Tutorials:

Teil 1 (was Sie gerade lesen):

  • MongoDB-Schema-Design
  • Verwenden der Mongo-Shell zum Abfragen von Informationen
  • Verbinden Sie Ihre Datenbank mit Ihrem Node-Express-Server und schreiben Sie RESTful-APIs

Teil 2:

  • Verwenden von Socket.IO, um zu ermöglichen, dass Cop- und Zivilgeräte miteinander kommunizieren
  • Verwenden der Google Maps-API, um Zivilisten und Polizisten auf einer Karte anzuzeigen

Lass uns anfangen!

Entwickler verwenden MongoDB bereits seit einiger Zeit zum Erstellen von Anwendungen. Es hat eine flache Lernkurve und seine Vielseitigkeit ermöglicht es Entwicklern, Anwendungen schnell und einfach zu erstellen.

Ich persönlich mag MongoDB, weil es mir ermöglicht, schnell Prototypen für eine Idee zu erstellen, um Proof-of-Concept zu demonstrieren.

Bevor Sie beginnen, stellen Sie sicher, dass MongoDB und NodeJS installiert sind. Zum Zeitpunkt des Schreibens dieses Artikels ist die aktuelle Version von MongoDB 3.2.

Entwerfen des Schemas

Da Sie MongoDB verwenden, ist alles, was Sie darin speichern, eine Sammlung von Dokumenten.

Erstellen wir eine Sammlung mit dem Namen "CitizensData" zum Speichern von Bürgerinformationen und eine weitere Sammlung mit dem Namen "PoliceData" zum Speichern von Cops-Informationen. Öffnen Sie also Ihr Terminal und geben Sie mongo ein, um die mongo-Shell zu starten. Sobald es geöffnet ist, können Sie vorhandene Datenbanken in MongoDB anzeigen, indem Sie Folgendes eingeben:

zeige dbs

Sie benötigen eine neue Datenbank, um Ihre App-Daten zu speichern. Nennen wir es myUberApp. Um eine neue Datenbank zu erstellen, können Sie Folgendes eingeben:

benutze myUberApp

Mit dem Befehl use wird eine neue Datenbank erstellt, wenn diese nicht vorhanden ist. In diesem Fall wird Mongo angewiesen, alle folgenden Befehle auf diese Datenbank anzuwenden.

Mongo speichert Dokumente in Sammlungen. Sammlungen sind wie Tabellen. Geben Sie Folgendes ein, um vorhandene Sammlungen anzuzeigen:

Sammlungen zeigen

Für den Polizisten könnte der Benutzername auch die Ausweis-ID sein. Sie können zur Authentifizierung ein Feld für die E-Mail-Adresse und ein Feld für das Passwort hinzufügen (das nicht angezeigt wird).

Gehen Sie zu diesem Link und speichern Sie den JSON-Datensatz für Cop-bezogene Informationen.

Geben Sie Folgendes in Ihr Terminal ein, um Daten aus dieser JSON-Datei zu importieren:

mongoimport --db myUberApp --collection polizeidaten --drop --file ./path/to/jsonfile.json

Bevor Sie mit dem Abfragen Ihrer Datenbank beginnen, müssen Sie zunächst ein wenig über die Funktionsweise von Indizes in MongoDB (oder einer anderen Datenbank) lernen.

Ein Index ist eine spezielle Anordnung von Daten oder Datenstrukturen, mit der Sie Informationen sehr effizient abfragen können. Auf diese Weise können Sie schnell Ergebnisse abrufen, ohne die gesamte Datenbank durchsuchen zu müssen.

Angenommen, Sie haben schülerbezogene Informationen in aufsteigender Reihenfolge ihres Namens in einem Buch gespeichert. Dies bedeutet, dass Sie einen Index für das Namensfeld haben. Auf diese Weise können Sie, wenn Sie Informationen von einer Person namens Tyrion abrufen mussten, deren Informationen schnell finden, ohne zuerst den Rest der Schüler durchzugehen.

Wenn Sie jedoch dieselben Informationen in aufsteigender Reihenfolge ihrer Größe speichern, wird es schwierig, Informationen für eine Person abzufragen, die ihren Namen verwendet. Dies kann viel Zeit in Anspruch nehmen, da die Schüler jetzt nicht in der Reihenfolge ihres Namens gespeichert werden und Sie möglicherweise mehrere Zeilen scannen und durchsuchen müssen.

Es werden jedoch auch andere Abfragen möglich. Rufen Sie beispielsweise Informationen von Schülern ab, deren Höhe zwischen 4 und 5 Fuß liegt. In diesem Fall konnten Tyrions Informationen schnell abgerufen werden, weil:

Verschiedene Datenbanken unterstützen verschiedene Arten von Indizes. Die vollständige Liste der Indizes, die MongoDB unterstützen, finden Sie hier.

Wenn Sie nun diesen Befehl eingeben:

 db.policeData.find (). hübsch ()

Hiermit erhalten Sie alle Dokumente zurück, die in der polizeilichen Datenerfassung vorhanden sind. Dies ist die gesamte Liste der Polizisten. (Die hübsche Funktion erleichtert das Lesen der Ausgabe).

Wenn Sie Informationen zu einem bestimmten Cop abrufen möchten, dessen Benutzer-ID 01 ist, können Sie db.policeData.find ({Benutzer-ID: „01“}) eingeben. Pretty ()

{"_id": ObjectId ("57e75af5eb1b8edc94406943"), "userId": "01", "displayName": "Cop 1", "phone": "01", "email": "cop01@gmail.com", " EarnedRatings ": 21," TotalRatings ": 25," Location ": {" Typ ":" Point "," Adresse ":" Kalyan Nagar, Bengaluru, Karnataka 560043, Indien "," Koordinaten ": [77.63997110000003, 13.0280047]} }}

Verwenden von MongoDB-Geodatenindizes

Mit Geodaten können Sie GeoJSON-Objekte in Dokumenten speichern.

GeoJSON-Objekte können vom verschiedenen Typ sein, z. B. Point, LineString und Polygon.

Wenn Sie die Ausgabe Ihres Befehls .find () beobachten, werden Sie feststellen, dass jeder Ort ein Objekt ist, in dem sich das Typfeld und das Koordinatenfeld befinden. Dies ist wichtig, denn wenn Sie Ihr GeoJSON-Objekt als Punkttyp speichern, können Sie mit dem Befehl $ close nach Punkten in bestimmter Nähe für einen bestimmten Längen- und Breitengrad suchen.

Um dies zu verwenden, müssen Sie einen 2dsphere-Index (bei dem es sich um einen Geodatenindex handelt) für das Standortfeld erstellen und ein Typfeld enthalten. Der 2dsphere-Index unterstützt Abfragen, die Geometrien auf einer erdähnlichen Kugel berechnen. Dies umfasst MongoDB-Geodatenabfragen: Abfragen zur Aufnahme, Schnittmenge und Nähe.

Geben Sie dies also in Ihre Mongo-Shell ein:

db.policeData.createIndex ({"location": "2dsphere"})

Um Dokumente von einem bestimmten Koordinatenpaar vom nächsten zum am weitesten entfernten abzurufen, müssen Sie einen Befehl mit der folgenden Syntax ausgeben:

db. .finden({ : {$ Near: {$ Geometrie: {Typ: "Punkt", Koordinaten: [ , ]}, $ minDistance: , $ maxDistance: } } }).ziemlich()

$ minDistance und $ maxDistance sind optionale Felder. Führen Sie Folgendes aus, um alle Polizisten zu ermitteln, die sich innerhalb von 2 Kilometern von 12.9718915 und 77.64115449999997 befinden.

db.policeData.find ({Ort: {$ in der Nähe: {$ Geometrie: {Typ: "Punkt", Koordinaten: [77.64115449999997, 12.9718915]}, $ maxDistance: 2000}}). hübsch ()

Und das war's - Sie finden eine Liste der zurückgegebenen Dokumente in der Ausgabe!

Perfekt! Versuchen wir nun, dasselbe mit einem Webserver zu tun. Laden Sie diese package.json-Datei herunter und speichern Sie sie im Stammverzeichnis Ihres Projektordners (stellen Sie sicher, dass Sie package.json genannt haben). Anschließend kopieren Sie sie in Ihrem Terminal in das Verzeichnis, in dem sich die Datei befindet, und führen Sie sie aus

sudo npm installieren

Eine kurze Erklärung zu einigen der Pakete, die Sie verwenden werden:

  • Express ist ein Webframework für NodeJS. Es verfügt über zahlreiche APIs, Dienstprogramme und Middlewares in seinem Ökosystem, mit denen Sie Ihre Anwendung erstellen können.
  • body-parser analysiert eingehende Anforderungskörper in einer Middleware vor Ihren Handlern, die unter der Eigenschaft req.body verfügbar sind. Sie benötigen dies, damit Sie POST-Anfragen bearbeiten können.
  • Der Unterstrich vereinfacht das Schreiben von JavaScript. Wenn Sie möchten, können Sie auch eine andere Bibliothek verwenden.
  • Mit socket.io können Sie Web-Sockets in Ihrer Node-Anwendung verwenden.
  • mongodb ist der offizielle NodeJS-Treiber für MongoDB. Es hilft Ihrer Node-App, mit Ihrer Datenbank zu kommunizieren.

Die Datei package.json enthält auch andere Module. Sie benötigen sie beim Erstellen einer vollständigen App, aber ich werde mich darauf konzentrieren, wie Sie den Mongodb-Treiber in Ihrer Express-App zum Ausführen von Abfragen verwenden. Einige der anderen Module tun Folgendes:

  • async ist ein Dienstprogramm für den Umgang mit asynchronem Code in NodeJS. Es hilft Ihnen, Rückrufhölle zu vermeiden.
  • Debug ist eine Debugging-Bibliothek. Dieses praktische Tool hilft beim Debuggen Ihrer Programme ohne die Verwendung hässlicher Ausgaben für console.log-Anweisungen.
  • redis ähnelt dem mongodb treiber. Damit kann Ihre NodeJS-App mit Ihrer Redis-Datenbank kommunizieren.
  • connect-redis ist ein Sitzungsspeicher, der Redis zum Verwalten von Sitzungen verwendet. Sie benötigen dies später, wenn Sie sich für Benutzerkonten entscheiden.

Bevor Sie Code schreiben, ist es hilfreich, ihn zuerst zu organisieren. Im Moment können Sie zwei Dateien verwenden:

  • Eine Datei zum Schreiben Ihrer API-Endpunkte
  • Eine Datei, die Datenbanktreiber für datenbankbezogene Vorgänge verwendet. Der Route-Handler würde entscheiden, welche Funktion aus der Datenbankdatei aufgerufen werden soll. Sobald eine Abfrage durchgeführt wurde, werden die Ergebnisse mithilfe einer Rückruffunktion an Ihren Routenhandler zurückgegeben.

Mal sehen, wie das aussieht, wenn Sie Ihren Code schreiben:

In diesem Beispiel erstellen Sie eine neue Instanz des MongoClient-Objekts aus dem Mongodb-Modul. Sobald der Webserver gestartet ist, stellen Sie mithilfe der Verbindungsfunktion, die von Ihrer MongoClient-Instanz bereitgestellt wird, eine Verbindung zu Ihrer MongoDB-Datenbank her. Nachdem die Verbindung initialisiert wurde, wird im Rückruf eine Db-Instanz zurückgegeben.

Sie können jetzt sowohl die App- als auch die DB-Instanz an die Initialisierungsfunktion Ihrer Datei route.js übergeben.

Als Nächstes müssen Sie eine neue Datei mit dem Namen route.js erstellen und diesen Code hinzufügen:

Funktionsinitialisierung (App, DB) { 
// Eine GET-Anfrage an / cops sollte die nächsten Cops in der Nähe zurückgeben. app.get ('/ cops', Funktion (req, res) {
/ * extrahiere die Längen- und Breitengradinformationen aus der Anfrage. Holen Sie dann die nächsten Cops mithilfe der Geodatenabfragen von MongoDB und senden Sie sie an den Client zurück. * /
}); }}
exports.initialize = initialize;

Damit dies funktioniert, müssen Sie die Koordinaten in Ihrer Anfrage als Abfragezeichenfolgen übergeben. Sie werden Ihre Datenbankoperationen auch in eine andere Datei schreiben. Erstellen Sie also eine neue Datei db-operation.js und schreiben Sie Folgendes:

Funktion fetchNearestCops (Datenbank, Koordinaten, Rückruf) {db.collection ('polizeidaten'). createIndex ({"location": "2dsphere"}, function () {db.collection ("polizeidaten"). find ({location: { $ Near: {$ Geometrie: {Typ: "Punkt", Koordinaten: Koordinaten}, $ maxDistance: 2000}}}. toArray (Funktion (err, Ergebnisse) {if (err) {console.log (err)} else {Rückruf (Ergebnisse);}});}); }}
exports.fetchNearestCops = fetchNearestCops;

Diese Funktion akzeptiert drei Argumente: eine Instanz von db, ein Array, das Koordinaten in der Reihenfolge enthält [ , ] und eine Rückruffunktion, an die die Ergebnisse Ihrer Abfrage zurückgegeben werden.

Der createIndex stellt sicher, dass ein Index für das angegebene Feld erstellt wird, wenn er nicht vorhanden ist. Sie können diesen Index daher überspringen, wenn Sie vor der Abfrage bereits einen Index erstellt haben.

Jetzt müssen Sie nur noch diese Funktion in Ihrem Handler aufrufen. Ändern Sie also Ihren Code route.js wie folgt:

var dbOperations = require ('./ db-operator');
Funktionsinitialisierung (App, DB) {
    // '/cops?lat=12.9718915&&lng=77.64115449999997' app.get ('/ cops', function (req, res) {
// Konvertiere die Abfragezeichenfolgen in Numbers var latitude = Number (req.query.lat); var longitude = Number (req.query.lng);
        dbOperations.fetchNearestCops (db, [Länge, Breite], Funktion (Ergebnisse) {
// die Ergebnisse in Form von JSON an den Client zurückgeben res.json ({cops: results}); });
}); }}
exports.initialize = initialize;

Und das ist es! Lauf

Knoten app.js. 

Öffnen Sie dann von Ihrem Terminal aus Ihren Browser und klicken Sie auf http: // localhost: 8000 / cops? lat = 12.9718915 && lng = 77.64115449999997

Abhängig von den von Ihnen übergebenen Abfragezeichenfolgen sollten Sie entweder eine JSON-Antwort mit einem leeren Array oder ein Array mit Cop-Daten erhalten!

Dies ist das Ende von Teil 1. In Teil 2 werden Sie eine Stufe höher gehen und versuchen, ein Notsignal an nahegelegene Polizisten zu senden. Dann werden Sie herausfinden, wie ein Polizist mit socket.io auf das Signal reagieren kann. Sie sehen auch, wie Sie den Standort des Bürgers auf einer Karte anzeigen.

Schauen Sie sich in der Zwischenzeit den Quellcode auf Github an!

Vielen Dank an Quincy Larson, die mir geholfen hat, diesen Artikel besser zu machen.

UPDATE: Sie können diesen Artikel und die nachfolgenden Teile auch in meinem Blog lesen!