فصل جدید؛ نگاهی عمیق به Create

Take a Deep Look at Create

02 اسفند 1400
درسنامه درس 29 از سری دوره جامع آموزش MongoDB
MongoDB: فصل جدید، نگاهی عمیق به Create (قسمت 29)

در فصل های قبل با تنظیمات پیکربندی سرور آشنا شدیم و همچنین در مورد مقدمات و مسائل ابتدایی CRUD صحبت کردیم اما در این فصل و چند فصل بعدی می خواهیم این دستورات را به طور عمیق و جزئی بررسی کنیم و تمام زوایای پنهان آن ها را یاد بگیریم. این فصل مخصوص Create (ساختن اسناد و همچنین وارد کردن آن ها از پایگاه های داده دیگر) است و زمانی که این فصل تمام شود به ترتیب نگاهی عمیق تر به عملیات های Read (خواندن اطلاعات) و Update (ویرایش و به روز رسانی) و Delete (حذف داده ها) خواهیم داشت.

تا اینجا برای ساخت document های جدید دو متد زیر را داشتیم:

  • insertOne که فقط یک document (سند) را ثبت می کند.
  • insertMany که چندین document (سند) را همزمان ثبت می کند.

البته باید بدانید که دستوری به نام ()insert نیز داریم که قدیمی است (قبل از معرفی insertOne و insertMany) و هر دو کار را می کند؛ یعنی هم می تواند یک سند و هم چندین سند را اجرا کند. از آنجایی که این دستور قدیمی است و همچنین احتمال خطای ما در کار کردن با آن بالا می رود من آن را کنار می گذارم. از معایب آن می توان به موارد زیر اشاره کرد:

  • واضح نبودن کد در نگاه اول: با insert اصلا معلوم نبود که می خواهیم یک سند یا چند سند را وارد collection خود کنیم.
  • احتمال خطای بیشتر: در بسیاری از مواقع انتظار داریم که چندین سند را ثبت کند اما تمام سند ها را به عنوان یک سند بزرگ می نویسیم و فقط یک سند ثبت می شود.
  • پس از ثبت یک سند، id آن به ما داده نمی شود مگر اینکه خودمان به صورت دستی از pretty استفاده کنیم. در برنامه های واقعی آزار دهنده است که برای دریافت یک id ساده یک کوئری جداگانه داشته باشیم. سرعت برنامه ما در این حالت واقعا کم می شود.

بنابراین ما روی insertOne و insertMany و همچنین دستوری به نام mongoimport (برای وارد کردن داده ها از یک پایگاه داده دیگر) تمرکز خواهیم کرد.

برای شروع مثل همیشه تمام پایگاه های داده قبل را حذف کرده و از صفر شروع می کنیم. سپس یک پایگاه داده جدید به نام contactData را می سازم:

use contactData

ما می دانیم که می توانیم با استفاده از دستور insertOne یک سند جدید را در پایگاه داده خودمان ثبت کنیم. من collection ای به نام persons را تعریف می کنم و می گویم:

db.persons.insertOne({name: "Amir", age: 24, hobbies: ["programming", "working out"]})

همچنین می دانیم که برای ایجاد چند سند باید از insertMany استفاده کرد اما یادتان باشد که حتی اگر فقط یک سند را به insertMany بدهید باز هم بدون مشکل اجرا می شود. مسئله این است که insertOne فقط یک سند و insertMany یک سند و بیشتر را قبول می کند.

نکته بعدی ما در مورد اضافه کردن موارد تکراری است. به کد زیر توجه کنید:

db.hobbies.insertMany([{_id: "sports", name: "Sports"}, {_id: "cooking", name: "Cooking"}, {_id: "cars", name: "Cars"}])

همانطور که در کد بالا مشخص است، ما id ها را خودمان تعریف کرده ایم و نگذاشته ایم که MongoDB آن را به صورت خودکار بسازد. با اجرای کد زیر می توانیم نتیجه را ببینیم:

db.hobbies.find().pretty()

نتیجه:

{ "_id" : "sports", "name" : "Sports" }
{ "_id" : "cooking", "name" : "Cooking" }
{ "_id" : "cars", "name" : "Cars" }

بنابراین هر سه سند ما به درستی اضافه شده است و فعلا چیز جدیدی نداریم. این اسناد، در collection ای به نام hobbies (به معنی تفریحات یا فعالیت های مورد علاقه) قرار دارند. sports یعنی فعالیت های ورزشی، cooking یعنی آشپزی و cars یعنی ماشین ها و رانندگی. حالا فرض کنید من کد زیر را اجرا کنم:

db.hobbies.insertMany([{_id: "yoga", name: "Yoga"}, {_id: "cooking", name: "Cooking"}, {_id: "hiking", name: "Hiking"}])

اگر به این کد دقت کنید متوجه موضوعی می شوید. من آیتم دوم را دوباره همان cooking گذاشته ام بنابراین دارای id تکراری است! به نظر شما در چنین حالتی چه اتفاقی می افتد؟ آیا کوئری اجرا می شود یا خطا می گیریم؟ با اجرای این کد خطای زیر را می گیریم (من فقط قسمتی از خطا را می آورم):

        "writeErrors" : [
                {
                        "index" : 1,
                        "code" : 11000,
                        "errmsg" : "E11000 duplicate key error collection: contactData.hobbies index: _id_ dup key: { _id: \"cooking\" }",
                        "op" : {
                                "_id" : "cooking",
                                "name" : "Cooking"
                        }
                }
        ],
        "writeConcernErrors" : [ ],
        "nInserted" : 1,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
}) :

یعنی در ایندکس 1 (عضو دوم - ایندکس ها از صفر شروع می شوند) خطایی اتفاق افتاده است. چه نوع خطایی؟ اگر به errmsg نگاه کنیم مشخص می شود که duplicate key error داریم یعنی خطایی که key های ما یکی هستند (همان id_ ما در اینجا) و id ها اجازه تکراری بودن ندارند. مسئله جالب تر این است که در انتهای این کد برای مقدار nInserted (اسناد ثبت شده) عدد 1 آمده است! یعنی Yoga اضافه شده است! به عبارت دیگر Yoga (عنصر اول) قبل از خطا (عنصر دوم) آمده است بنابراین مشکلی ندارد و اضافه می شود اما از عنصر دوم به بعد دیگر چیزی اضافه نخواهد شد (می توانید با find.pretty این موضوع را تست کنید).

ما به این مسئله ordered inserts می گوییم (یعنی insert ها یا ورودی های ترتیبی) چرا که به ترتیب ثبت می شوند. حالا اگر ما چنین رفتاری را نخواهیم چطور؟ آیا می توان آن را غیر فعال کرد؟ بله!

db.hobbies.insertMany([{_id: "yoga", name: "Yoga"}, {_id: "cooking", name: "Cooking"}, {_id: "hiking", name: "Hiking"}], {ordered: false})

شیء دومی که به insertMany پاس داده ایم مربوط به تنظیمات آن است. در اینجا باید خصوصیتی به نام ordered را روی false بگذاریم تا حتی با وجود خطا باز هم ادامه دهد. حالا اگر دستور بالا را اجرا کنیم دو خطا می گیریم: یکی مربوط به Yoga (از دستور قبل اضافه شده بود) و همچنین Cooking. همین که دو خطا گرفته ایم یعنی پس از ایجاد خطای اول، کوئری متوقف نشده است بلکه به کارش ادامه می دهد. همچنین مورد آخر که hiking بود و در hobbies وجود نداشت، حالا اضافه می شود.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش MongoDB توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
آخرین سوالات کاربران
5451218 در 4 سال قبل پرسیده:
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو