A MongoDB + Mongoose használata a Node.js-sel - Legjobb gyakorlatok a háttérvégi fejlesztők számára

A MongoDB kétségtelenül napjaink egyik legnépszerűbb NoSQL adatbázis-választása. És nagyszerű a közössége és az ökoszisztémája.

Ebben a cikkben áttekintjük a MongoDB és a Mongoose Node.js használatával történő beállításakor követendő bevált módszereket.

A cikk előfeltételei

Ez a cikk az egyik része a codedamn háttér-tanulási útjának, ahol a backend alapjaiból indulunk ki, és azokat részletesen bemutatjuk. Ezért feltételezem, hogy van némi tapasztalata a JavaScript (és a Node.js) használatával kapcsolatban.

Jelenleg itt vagyunk:

Ha nagyon kevés tapasztalata van a Node.js / JavaScript-ről vagy általában a háttérprogramról, akkor ez valószínűleg jó hely a kezdéshez. Ingyenes tanfolyamot is talál a Mongoose + MongoDB + Node.js webhelyen. Merüljünk be.

Miért van szükséged Mongúzra?

Annak megértéséhez, hogy miért van szükségünk Mongoose-ra, értsük meg, hogyan működik a MongoDB (és egy adatbázis) az architektúra szintjén.

  • Van adatbázis-kiszolgálója (például a MongoDB közösségi szerver)
  • Node.js szkript fut (folyamatként)

A MongoDB szerver (általában) egy TCP foglalatot hallgat, és a Node.js folyamat TCP kapcsolaton keresztül csatlakozhat hozzá.

De a TCP tetején a MongoDB saját protokollal is rendelkezik annak megértéséhez, hogy az ügyfél (a Node.js folyamatunk) pontosan mit akar az adatbázisnak.

Ehhez a kommunikációhoz ahelyett, hogy megtanulnánk azokat az üzeneteket, amelyeket a TCP rétegre kell küldenünk, elvonatkoztatunk egy "driver" szoftver segítségével, amelyet ebben az esetben MongoDB drivernek hívunk. A MongoDB illesztőprogram itt érhető el npm csomagként.

Ne feledje, hogy a MongoDB illesztőprogram felelős az alacsony szintű kommunikációs kérelem / válaszok összekapcsolásáért és kivonásáért - de ez csak fejlesztőként vezet el.

Mivel a MongoDB egy sémátlan adatbázis, így sokkal több energiát ad, mint amennyire kezdőként szüksége van. A nagyobb teljesítmény nagyobb felületet jelent a dolgok rosszra fordításához. Csökkentenie kell a hibáinak és csavarjainak felületét, amelyeket a kódjában megtehet. Kell még valami.

Találkozz Mongoose-val. A Mongoose egy absztrakció a natív MongoDB illesztőprogram felett (a fent említett npm csomag).

Az absztrakciókkal kapcsolatos általános szabály (ahogy megértem), hogy minden absztrakcióval elveszít valamilyen alacsony szintű működési erőt. De ez nem feltétlenül jelenti azt, hogy rossz. Néha 1000x + növeli a termelékenységet, mert soha nem kell teljes mértékben hozzáférnie az alapul szolgáló API-hoz.

Egy jó módszer arra gondolni, hogy technikailag létrehoz egy valós idejű csevegőalkalmazást C-ben és Pythonban egyaránt.

A Python példát sokkal könnyebben és gyorsabban lehetne fejlesztőként megvalósítani nagyobb termelékenység mellett.

Lehet, hogy a C hatékonyabb, de hatalmas költségekkel jár a termelékenységben / a fejlesztés sebességében / hibákban / összeomlásokban. Ráadásul többnyire nincs szüksége a C-energiával a webaljzatok megvalósításához.

Hasonlóképpen, a Mongoose segítségével korlátozhatja az alacsonyabb szintű API-hozzáférés felületét, de rengeteg potenciális nyereséget és jó DX-t nyithat meg.

A Mongoose + MongoDB csatlakoztatása

Először nézzük meg gyorsan, hogyan kell csatlakozni a MongoDB adatbázisához 2020-ban a Mongoose segítségével:

mongoose.connect(DB_CONNECTION_STRING, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false })

Ez a kapcsolatformátum biztosítja, hogy a Mongoose új URL-elemzőjét használja, és hogy ne használjon elavult gyakorlatokat. Itt olvashat részletesebben ezekről a megszüntetési üzenetekről, ha úgy tetszik.

A mongúz műveletek végrehajtása

Most folytassuk és gyorsan megvitassuk a mongúzokkal a műveleteket, és azt, hogy miként kell végrehajtanod őket.

A Mongoose két dologra ad lehetőséget:

  1. Kurzor alapú lekérdezés
  2. Teljes lekérdezés

Kurzor alapú lekérdezés

Kurzor alapú lekérdezés azt jelenti, hogy egyszerre egyetlen rekorddal dolgozik, miközben egyszerre egyetlen vagy egy köteg dokumentumot hoz be az adatbázisból. Ez egy hatékony módszer hatalmas mennyiségű adat kezelésére korlátozott memóriakörnyezetben.

Képzelje el, hogy 10 GB teljes méretű dokumentumokat kell elemeznie egy 1 GB / 1core felhőszerveren. Nem tudja lekérni a teljes gyűjteményt, mert az nem fog illeszkedni a rendszeréhez. A kurzor itt jó (és az egyetlen?) Opció.

Teljes lekérdezés lekérdezés

Ez az a típusú lekérdezés, ahol egyszerre kapja meg a lekérdezés teljes válaszát. Nagyrészt ezt fogja használni. Ezért itt főleg erre a módszerre fogunk összpontosítani.

Hogyan kell használni a mongúz modelleket

A modellek a mongúz nagyhatalma. Segítenek a "séma" szabályok betartatásában, és zökkenőmentesen integrálják a csomópont-kódot az adatbázis-hívásokba.

A legelső lépés egy jó modell meghatározása:

import mongoose from 'mongoose' const CompletedSchema = new mongoose.Schema( { type: { type: String, enum: ['course', 'classroom'], required: true }, parentslug: { type: String, required: true }, slug: { type: String, required: true }, userid: { type: String, required: true } }, { collection: 'completed' } ) CompletedSchema.index({ slug: 1, userid: 1 }, { unique: true }) const model = mongoose.model('Completed', CompletedSchema) export default model 

Ez az egyik kivágott példa közvetlenül a codedamn kódbázisából. Néhány érdekes dolgot érdemes megjegyezned itt:

  1. Próbálja megtartani required: trueaz összes szükséges mezőt. Ez óriási fájdalomcsillapító lehet számodra, ha nem használsz egy statikus típusellenőrző rendszert, például a TypeScript-et, hogy az objektum létrehozása során a helyes tulajdonságnevekkel segítsen. Ráadásul az ingyenes validálás is nagyon jó.
  2. Adjon meg indexeket és egyedi mezőket. uniquetulajdonság egy sémán belül is hozzáadható. Az indexek tág témakörök, ezért itt nem térek ki mélyre. De nagy léptékben valóban sokat segíthetnek a kérdéseinek felgyorsításában.
  3. Határozottan határozza meg a gyűjtemény nevét. Bár Mongoose automatikusan megadhat egy gyűjtemény nevet a modell neve alapján ( Completedpéldául itt), véleményem szerint ez túl sok absztrakció. Legalább tudnia kell a kódbázisában található adatbázisnevekről és gyűjteményekről.
  4. Ha lehetséges, korlátozza az értékeket az enums használatával.

A CRUD műveletek végrehajtása

A CRUD jelentése C reate, R ead , U pdate és D elete . Ez a négy alapvető lehetőség, amellyel bármilyen típusú adatkezelést elvégezhet egy adatbázisban. Gyorsan lássunk néhány példát ezekre a műveletekre.

A Create művelet

Ez egyszerűen azt jelenti, hogy új rekordot kell létrehozni egy adatbázisban. Használjuk a fent definiált modellt a rekord létrehozásához:

try { const res = await CompletedSchema.create(record) } catch(error) { console.error(error) // handle the error }

Ismét néhány utalás itt:

  1. A visszahívások helyett használja az async-await funkciót (kellemes a szem, nem jelent úttörő teljesítményelőnyt)
  2. Használjon próbálkozási blokkokat a lekérdezések körül, mert a lekérdezése több okból is meghiúsulhat (ismétlődő rekord, helytelen érték stb.)

Az Olvasás művelet

Ez azt jelenti, hogy a meglévő értékeket kiolvassuk az adatbázisból. egyszerű, csak úgy, mint amilyennek hangzik, de van néhány góca, amelyet tudnia kell a Mongoose-szal:

const res = await CompletedSchema.find(info).lean()
  1. Látja lean()ott a függvényhívást? Nagyon hasznos a teljesítményhez. Alapértelmezés szerint a Mongoose feldolgozza a visszaküldött dokumentum (oka) t az adatbázisból, és hozzáadja a varázslatos módszereit (például .save)
  2. Használatakor a .lean()Mongoose egyszerű JSON objektumokat ad vissza memória- és erőforrásigényes dokumentumok helyett. Gyorsabbá és olcsóbbá teszi a lekérdezéseket a CPU-n is.
  3. Kihagyhatja azonban, .lean()ha valóban az adatok frissítésén gondolkodik (ezt majd meglátjuk)

A frissítési művelet

Ha már van magánál egy Mongoose-dokumentum (anélkül, hogy azzal lőne .lean()), egyszerűen folytathatja az objektum tulajdonságának módosítását, és elmentheti object.save():

const doc = await CompletedSchema.findOne(info) doc.slug = 'something-else' await doc.save()

Ne feledje, hogy itt két adatbázis-hívás történt. Az első be van kapcsolva findOne, a második pedig be van kapcsolva doc.save.

Ha teheti, mindig csökkentenie kell az adatbázisba kerülő kérelmek számát (mert ha összehasonlítja a memóriát, a hálózatot és a lemezt, akkor a hálózat szinte mindig a leglassabb).

A másik esetben használhat ilyen lekérdezést:

const res = await CompletedSchema.updateOne(, ).lean()

and it will only make a single call to the database.

The Delete Operation

Delete is also straightforward with Mongoose. Let's see how you can delete a single document:

const res = await CompletedSchema.deleteOne()

Just like updateOne, deleteOne also accepts the first argument as the matching condition for the document.

There is also another method called deleteMany which should be used only when you know you want to delete multiple documents.

In any other case, always use deleteOne to avoid accidental multiple deletes, especially when you're trying to execute queries yourself.

Conclusion

This article was a simple introduction to the Mongoose and MongoDB world for Node.js developers.

If you enjoyed this article, you can step up your game even more as a developer by following the codedamn backend learning path. Please feel free to reach out to me on Twitter for any feedback!