Showing posts with label mongoose. Show all posts
Showing posts with label mongoose. Show all posts

How Does 2 Problems Live Together In Peace

گاهی دو مشکل کنار هم در سورس کد می توانند به نحو جالبی همدیگر را بپوشانند و باعث نتایج تقریبا درست شوند. چیزی شبیه اتفاقی که برای for-in در جاوااسکریپت و find در mongodb در کنار هم می افتد.


مقدمه اول
در جاواسکریپت حلقه ای به نام for-in داریم که کارش Enumeration در یک آرایه است. مثلا:

var list = [1,2,3];
for( var item in list){
   ...
}

تا اینجا چیزی شبیه foreach است که در خیلی زبانها داریم. اما فرقی که وجود دارد این است که for-in روی کلیدها Enumeration انجام می دهد. برای نمونه در مثال بالا مقادیر item عبارت خواهد بود از 0, 1, 2. چرا که برای یک آرایه کلیدها همان اندیس های آرایه هستند. یا به عنوان نمونه ای دیگر:

var product = { name:'MXD56', price:56, weight:32.4 }
for( var key in product){
   console.log(key)
}

Output: 
name
price
weight
البته استفاده از for-in زیاد توصیه نمی شود و در نکوهش استفاده از آن مطالبی زیادی نوشته شده است.


مقدمه دوم
اگر بخواهید در Collection های mongoDB به دنبال row هایی با یک مقدار خاص بگردید، احتمالا از دستوری شبیه این استفاده می کنید:

find( {field:value} )

اما وقتی value از نوع undefined باشد، شرط در نظر گرفته نمی شود و تمام row ها برگردانده می شود.
حالا یک نمونه پیچیده تر را بررسی می کنیم. اگر یک آرایه از مقادیر داشته باشید (مثلا به اسم list ) و بخواهید تمام row هایی را استخراج کنید که مقدار فیلد مشخصی از آنها یکی از مقادیر این آرایه باشد، از چنین دستوری استفاده می کنید:

find( { field : { $in : list }}

هنگام استفاده از mongoDB در دو حالت عجیب ولی منطقی زیر تمام row ها به عنوان نتیجه جست و جو برگردانده می شوند:
1- وقتی به عنوان مقدار فیلد مورد جست و جو undefined را وارد کنید؛ مثل این:

find({email:undefined)


2- و حالت کمی پیچیده تر، وقتی بخواهید مقدار فیلدی برابر یکی از مقادیر یک آرایه باشد و در آن آرایه مقادیر undefined داشته باشید و همچنین اسم فیلد را هم اشتباه زده باشید؛ مثلا _email به جای email:

find({_email:{$in:[undefined]}​})

مقدمه سوم
حالا فرض کنید در nodejs می خواهید از یک collection آن row هایی که یک فیلدشان مقدار خاصی دارند را پیدا کنید و در این بین با تصوری که از ForEach در سایر زبان ها دارید ( که خود object ها را بر می گرداند ) از for-in استفاده کنید(مشکل اول) و از طرفی اسم فیلد مورد نظر را هم اشتباه بزنید(مشکل دوم):

var items = [ {ID:123} , {ID:456} , {ID:789} ];
var IDList = [];
for( var item in items){
   IDList.push( item.ID );
}
mycollection.find( { ID : {$in : IDList } } ). ...


تمام row های collection به عنوان نتیجه برگردانده می شود. علت این است که در هر اجرای for-in مقدار item برابر اندیس های آرایه items خواهد بود؛ یعنی 0, 1 , 2. و این مقادیر فیلدی به نام ID ندارند. پس 3 تا مقدار undefined در آرایه IDList وارد می شود. در نهایت find هم در یک آرایه از undefined ها برای وجود مقدار فیلد ID می گردد ( که نام فیلد را هم اشتباها ID است و در collection چنین فیلدی وجود ندارد) و این یعنی شرطی که نادیده گرفته می شود ( یا به عبارتی دیگر شرطی همیشه درست! ).



نتیجه
گاهی ممکن است دو مشکل بنیادین در کنار هم ( 1- استفاده اشتباه از for-in و 2- استفاده از مقدار undefined برای جست و جو در mongoDB ) تقریبا درست کار کنند!

Mongoose 3.8.3 and a problem in 'git push' (on Heroku Server)



امروز صبح قصد push کردن آخرین تغییرات به سرور Heroku را داشتم که با خطای زیر رو به رو شدم:

npm http GET https://registry.npmjs.org/mongoose/-/mongoose-3.8.3.tgz
npm http 404 https://registry.npmjs.org/mongoose/-/mongoose-3.8.3.tgz
npm ERR! fetch faild https://registry.npmjs.org/mongoose/-/mongoose-3.8.3.tgz
npm ERR! Error: 404 Not Found
npm ERR!     at null.<anonymous> (███\nodejs\node_modules\npm\lib\utils\fetch.js:47:16)
npm ERR!     at EventEmitter.emit (events.js:126:20)
npm ERR!     at WriteStream.flush (fs.js:1529:12)
npm ERR!     at Object.oncomplete (fs.js:297:15)
npm ERR! If you need help, you may report this log at:
npm ERR!     <http://github.com/isaacs/npm/issues>
npm ERR! or email it to:
npm ERR!     <npm-@googlegroups.com>

البته این تنها قسمتی آغازین پیغام بود و چند صد خط بعد از آن نیز در خروجی چاپ شد که مربوط به مشکلات ناشی از این خطا بودند. این خطا پس از اجرای دستور push به سرور Heroku به عنوان خروجی این دستور از سرور بر می گشت. با وجود بررسی هایی که انجام دادم تغییراتی که در کد ایجاد شده بود هیچ ارتباطی با این خطا نداشت.
خطا وقتی ایجاد می شد که Heroku قصد داشت ماژول mongoose را با دستور npm دریافت کند. هر چند تا دیشب این دریافت با موفقیت انجام می شد، ولی حالا با خطا همراه بود.
پس از کمی بررسی و سر زدن به سایت npmjs.org متوجه شدم که نسخه ای جدید از mongoose یک ساعت قبل منتشر شده است و به نظر می رسید نسخه جدید مشکل را ایجاد کرده است.



به سراغ فایل package.json رفتم و متوجه شدم برای mongoose هیچ نسخه خاصی مشخص نشده و طبعا npm سعی می کند آخرین نسخه را دریافت کند:
"dependencies": {
    ...
    "mongoose": "*",
     ...
  },
شروع به پیدا کردن نسخه سالمی از mongoose کردم. ابتدا دستور
npm install mongoose@3.8.3
با خطای مشابه رو به رو شد ولی دستور
npm install mongoose@3.8.1
به درستی ماژول را دریافت کرد.
با قرار دادن نسخه 3.8.1 ( آخرین نسخه که درست کار میکرد) و push مجدد، مشکل بر طرف شد.

هر چند استفاده از * به جای نسخه مشخص یا محدوده برای نسخه قابل قبول ماژول، بسیار راحت تر است، ولی گاهی هم مشکلاتی را ایجاد می کند که باعث اتلاف وقت بیهوده می شود.