Menu

MongoDB עם Node.js: דוגמאות driver ‏(find, insert, update)

עובדים עם MongoDB מ-Node.js דרך ה-driver הרשמי mongodb: מתחברים עם MongoClient, ואז מוסיפים, מוצאים, מעדכנים ומוחקים documents ב-collection, הכל עם async/await.

בדף הזה יש עורכים שאפשר להריץ. לערוך, להריץ ולראות את הפלט מיד.

כדי לעבוד עם MongoDB מ-Node.js, התקינו את ה-driver הרשמי (npm install mongodb), התחברו עם new MongoClient(uri), בחרו מסד נתונים עם client.db('name') ו-collection עם db.collection('name'). כל פעולה (insertOne, find, updateOne, deleteOne) מחזירה promise, כך שעושים לה await. documents נכנסים ויוצאים כאובייקטי JavaScript רגילים.

הוא מדפיס [ 'Dune', 'Neuromancer', 'Hyperion' ]. מסד הנתונים shop וה-collection ‏books לא היו קיימים קודם: MongoDB יוצר אותם בהוספה הראשונה, ו-toArray() טוען כל document שה-cursor של find() מצביע עליו.

חיפוש documents עם פילטרים ו-projection

פילטר הוא אובייקט שמתאר את ה-documents שאתם רוצים. ערכים רגילים מתאימים בדיוק; אופרטורים כמו $gt, $lt, $in ו-$regex נכנסים לאובייקט מקונן. ה-projection בארגומנט השני בוחר אילו שדות חוזרים.

recent מחזיק את שני הספרים החדשים ביותר אחרי 1960, ‏Hyperion ואז Neuromancer, רק עם title ו-year; ‏findOne מחזיר את ההתאמה הראשונה (או null), ו-countDocuments סופר 2 ספרים שעולים 10 או יותר. שנו את $gt: 1960 ל-$gt: 1985 ורק Hyperion יישאר.

עדכון ומחיקה

updateOne(filter, update) משנה את ה-document התואם הראשון. העדכון משתמש באופרטורים: $set מחליף שדות, $inc מוסיף למספר, $unset מסיר שדה ו-$push מוסיף למערך. updateMany ו-deleteMany פועלים על כל התאמה.

העדכון התאים ל-document אחד ושינה אותו, כך ש-Dune עולה עכשיו 10 עם 2 במלאי, ומחיקת הספר שאין לו מלאי משאירה 1. עדכון חייב להשתמש באופרטורים: העבירו { price: 10 } בלי $set וה-driver ידחה אותו (‏replaceOne היא הקריאה שמחליפה document שלם).

ObjectId ואינדקסים

כל document מקבל _id; כשלא מגדירים אחד, ה-driver יוצר ObjectId. כדי למצוא document לפי id שהגיע כמחרוזת (מ-URL, למשל), עטפו אותו ב-new ObjectId(id). אינדקס הופך חיפוש לפי שדה למהיר, ואינדקס unique גורם ל-MongoDB לסרב לכפילויות.

ObjectId הוא 24 תווים הקסדצימליים כמחרוזת, וחיפוש עם המחרוזת הרגילה לא מוצא כלום, ולכן השורה הזו מדפיסה null. ההוספה השנייה שוברת את האינדקס ה-unique ונכשלת עם הקוד 11000, וכך מזהים "האימייל כבר תפוס".

שימוש ב-MongoDB ב-API של Express

התחברו פעם אחת כשהשרת עולה ושתפו את ה-collection; אל תפתחו חיבור חדש לכל בקשה. ה-driver מחזיק pool של חיבורים ומשתמש בהם שוב.

GET /books מחזיר את שני הספרים, כל אחד עם _id. העתיקו id אחד ל-GET /books/<id> כדי להביא ספר בודד, או שלחו POST /books עם גוף JSON כמו {"title": "Foundation", "year": 1951} והציגו שוב את רשימת הספרים.

אפליקציה אמיתית קוראת את ה-connection string מתוך process.env.MONGODB_URI במקום לכתוב אותו בקוד.

אם אתם רוצים schemas וולידציה מעל ה-driver, ‏Mongoose (npm install mongoose) עוטף אותו:

const Book = mongoose.model('Book', new mongoose.Schema({ title: String, year: Number }));
await Book.create({ title: 'Dune', year: 1965 });

טעויות נפוצות

לשכוח את toArray(). find() מחזיר cursor, לא documents. הדפסה שלו מציגה אובייקט cursor; קראו ל-toArray(), או עברו עליו בלולאה עם for await.

התחברות בכל בקשה. כל new MongoClient פותח pool משלו. צרו client אחד בעלייה והשתמשו בו בכל מקום.

לא לסגור את ה-client בסקריפט. client פתוח משאיר את התהליך חי אחרי שהקוד שלכם סיים. קראו ל-await client.close() בסוף סקריפטים; שרת משאיר אותו פתוח לאורך כל חייו.

שאלות נפוצות

להשתמש ב-driver של mongodb או ב-Mongoose?

ה-driver הוא השכבה הרשמית והדקה יותר: עובדים עם אובייקטים רגילים ועם שפת השאילתות של MongoDB עצמה. Mongoose מוסיף מעליו schemas, ולידציה ו-models, וזה עוזר כשרוצים שכל document ייבדק. שניהם מדברים עם אותו מסד נתונים, ו-Mongoose משתמש ב-driver מתחת.

צריך ליצור מסד נתונים או collection קודם?

לא. MongoDB יוצר את שניהם בפעם הראשונה שמוסיפים אליהם document. client.db('shop') ו-db.collection('books') רק מחזירים handles.

איפה שמים את ה-connection string?

במשתנה סביבה כמו MONGODB_URI, שנקרא עם process.env.MONGODB_URI. ה-string של מסד נתונים מתארח מכיל סיסמה, ולכן אסור לעשות לו commit ל-repository.

למה find לא מחזיר documents כשאני מחפש לפי id?

_id נשמר כ-ObjectId, לא כמחרוזת, ולכן { _id: '65f1...' } לא תואם לכלום. המירו אותו קודם: { _id: new ObjectId(id) }.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל