Responsive Advertisement

Node.js์—์„œ MongoDB ์กฐ์ธํ•˜๊ธฐ: Lookup ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ ๊ฐ€์ด๋“œ

MongoDB๋Š” ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ JOIN๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ $lookup ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. $lookup์€ ํ•œ ์ปฌ๋ ‰์…˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฅธ ์ปฌ๋ ‰์…˜๊ณผ ๊ฒฐํ•ฉํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์ปฌ๋ ‰์…˜ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Node.js์™€ MongoDB๋ฅผ ์—ฐ๋™ํ•˜์—ฌ $lookup ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

MongoDB์˜ $lookup ๋ฉ”์„œ๋“œ๋ž€?

MongoDB์—์„œ $lookup์€ ๋‘ ๊ฐœ์˜ ์ปฌ๋ ‰์…˜์„ ์กฐํ•ฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ JOIN๊ณผ ์œ ์‚ฌํ•œ ์—ญํ• ์„ ํ•˜๋ฉฐ, ์ฃผ๋กœ aggregate ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. $lookup์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•œ ์ปฌ๋ ‰์…˜์˜ ํ•„๋“œ๋ฅผ ๋‹ค๋ฅธ ์ปฌ๋ ‰์…˜์˜ ํ•„๋“œ์™€ ๋งค์นญํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.

$lookup ๊ธฐ๋ณธ ๊ตฌ์กฐ

MongoDB์˜ $lookup ๊ธฐ๋ณธ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

{
  $lookup: {
    from: 'target_collection',        // ์กฐ์ธํ•  ์ปฌ๋ ‰์…˜์˜ ์ด๋ฆ„
    localField: 'current_field',      // ํ˜„์žฌ ์ปฌ๋ ‰์…˜์—์„œ ์ฐธ์กฐํ•  ํ•„๋“œ
    foreignField: 'target_field',     // ๋‹ค๋ฅธ ์ปฌ๋ ‰์…˜์—์„œ ์ผ์น˜ํ•  ํ•„๋“œ
    as: 'result_field'                // ๊ฒฐํ•ฉ๋œ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ํ•„๋“œ ์ด๋ฆ„
  }
}

์ด ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค:

  • from: ๋‹ค๋ฅธ ์ปฌ๋ ‰์…˜์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • localField: ํ˜„์žฌ ์ปฌ๋ ‰์…˜์˜ ํ•„๋“œ ์ค‘ ์กฐ์ธ์— ์‚ฌ์šฉํ•  ํ•„๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • foreignField: ๋‹ค๋ฅธ ์ปฌ๋ ‰์…˜์—์„œ ์ผ์น˜์‹œํ‚ฌ ํ•„๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • as: ์กฐ์ธ๋œ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋  ์ƒˆ๋กœ์šด ํ•„๋“œ์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

Node.js์™€ MongoDB ์—ฐ๋™ํ•˜๊ธฐ

MongoDB์—์„œ $lookup์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•˜๋ ค๋ฉด ๋จผ์ € Node.js์™€ MongoDB๋ฅผ ์—ฐ๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. mongodb ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

1. Node.js ํ”„๋กœ์ ํŠธ ์„ค์ •

MongoDB์™€ Node.js๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ๋จผ์ € Node.js ํ”„๋กœ์ ํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

$ mkdir myapp
$ cd myapp
$ npm init -y
$ npm install mongodb

2. MongoDB ์—ฐ๊ฒฐ ์„ค์ •

์ด์ œ MongoDB ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•˜๋Š” ๊ธฐ๋ณธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. MongoClient ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ MongoDB์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

// app.js

const { MongoClient } = require('mongodb');

// MongoDB ์—ฐ๊ฒฐ URL
const url = 'mongodb://localhost:27017'; // ๋กœ์ปฌ MongoDB URL
const client = new MongoClient(url);

// ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„
const dbName = 'myDatabase';

async function main() {
    try {
        // MongoDB ์—ฐ๊ฒฐ
        await client.connect();
        console.log('MongoDB์— ์„ฑ๊ณต์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');

        // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ ํƒ
        const db = client.db(dbName);
        console.log(`๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ${dbName} ์„ ํƒ๋จ.`);
        
    } catch (error) {
        console.error('MongoDB ์—ฐ๊ฒฐ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
    } finally {
        // MongoDB ์—ฐ๊ฒฐ ์ข…๋ฃŒ
        await client.close();
        console.log('MongoDB ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
    }
}

main();

์œ„ ์ฝ”๋“œ๋Š” MongoDB ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์„ ํƒํ•˜๋Š” ๊ธฐ๋ณธ ์„ค์ •์ž…๋‹ˆ๋‹ค. ์ด์ œ MongoDB์—์„œ $lookup์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

MongoDB์—์„œ ์ปฌ๋ ‰์…˜ ์กฐ์ธํ•˜๊ธฐ: $lookup ์‚ฌ์šฉ๋ฒ•

MongoDB์—์„œ $lookup์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ๊ฐœ ์ด์ƒ์˜ ์ปฌ๋ ‰์…˜์„ ๊ฒฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, users ์ปฌ๋ ‰์…˜๊ณผ orders ์ปฌ๋ ‰์…˜์„ ์กฐํ•ฉํ•˜์—ฌ ๊ฐ ์‚ฌ์šฉ์ž์™€ ๊ทธ๋“ค์ด ์ฃผ๋ฌธํ•œ ์ƒํ’ˆ ์ •๋ณด๋ฅผ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1. $lookup์„ ์‚ฌ์šฉํ•œ ๊ธฐ๋ณธ ์กฐ์ธ

๋‹ค์Œ ์ฝ”๋“œ๋Š” users ์ปฌ๋ ‰์…˜๊ณผ orders ์ปฌ๋ ‰์…˜์„ ์กฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์™€ ๊ทธ๋“ค์˜ ์ฃผ๋ฌธ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

// users์™€ orders ์ปฌ๋ ‰์…˜ ์กฐ์ธ ์˜ˆ์‹œ

async function joinUsersAndOrders() {
    try {
        await client.connect();
        console.log('MongoDB์— ์„ฑ๊ณต์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');

        const db = client.db(dbName);
        const usersCollection = db.collection('users');

        // users ์ปฌ๋ ‰์…˜๊ณผ orders ์ปฌ๋ ‰์…˜์„ ์กฐํ•ฉ
        const results = await usersCollection.aggregate([
            {
                $lookup: {
                    from: 'orders',           // ์กฐ์ธํ•  ์ปฌ๋ ‰์…˜ ์ด๋ฆ„
                    localField: '_id',        // users ์ปฌ๋ ‰์…˜์˜ ํ•„๋“œ
                    foreignField: 'user_id',  // orders ์ปฌ๋ ‰์…˜์—์„œ ๋งค์นญํ•  ํ•„๋“œ
                    as: 'user_orders'         // ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋  ํ•„๋“œ
                }
            }
        ]).toArray();

        console.log('์กฐ์ธ๋œ ๊ฒฐ๊ณผ:', results);
    } catch (error) {
        console.error('๋ฐ์ดํ„ฐ ์กฐ์ธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
    } finally {
        await client.close();
        console.log('MongoDB ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
    }
}

joinUsersAndOrders();

์œ„ ์ฝ”๋“œ๋Š” users ์ปฌ๋ ‰์…˜์—์„œ _id ํ•„๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ orders ์ปฌ๋ ‰์…˜์˜ user_id ํ•„๋“œ์™€ ์กฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์ฃผ๋ฌธ ์ •๋ณด๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋Š” user_orders ํ•„๋“œ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

2. ์—ฌ๋Ÿฌ ์ปฌ๋ ‰์…˜ ์กฐ์ธ

์—ฌ๋Ÿฌ ์ปฌ๋ ‰์…˜์„ ๋™์‹œ์— ์กฐ์ธํ•˜์—ฌ ๋” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, products ์ปฌ๋ ‰์…˜๊นŒ์ง€ ํ•จ๊ป˜ ์กฐํ•ฉํ•˜์—ฌ ๊ฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ฃผ๋ฌธํ•œ ์ œํ’ˆ์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋Š” ์˜ˆ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// users, orders, products ์ปฌ๋ ‰์…˜์„ ์กฐ์ธํ•˜๋Š” ์˜ˆ์‹œ

async function joinUsersOrdersAndProducts() {
    try {
        await client.connect();
        console.log('MongoDB์— ์„ฑ๊ณต์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');

        const db = client.db(dbName);
        const usersCollection = db.collection('users');

        const results = await usersCollection.aggregate([
            {
                $lookup: {
                    from: 'orders',            // ์ฒซ ๋ฒˆ์งธ ์กฐ์ธ
                    localField: '_id',
                    foreignField: 'user_id',
                    as: 'user_orders'
                }
            },
            {
                $lookup: {
                    from: 'products',          // ๋‘ ๋ฒˆ์งธ ์กฐ์ธ
                    localField: 'user_orders.product_id',
                    foreignField: '_id',
                    as: 'order_products'
                }
            }
        ]).toArray();

        console.log('์กฐ์ธ๋œ ๊ฒฐ๊ณผ:', results);
    } catch (error) {
        console.error('๋ฐ์ดํ„ฐ ์กฐ์ธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
    } finally {
        await client.close();
        console.log('MongoDB ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
    }
}

joinUsersOrdersAndProducts();

์ด ์ฝ”๋“œ๋Š” users, orders, products ์„ธ ๊ฐœ์˜ ์ปฌ๋ ‰์…˜์„ ์กฐํ•ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. $lookup์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ์‚ฌ์šฉ์ž์˜ ์ฃผ๋ฌธ ์ •๋ณด์™€ ์ œํ’ˆ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

MongoDB ์—ฐ๊ฒฐ ์ข…๋ฃŒ

๋ชจ๋“  ๋ฐ์ดํ„ฐ ์ž‘์—…์ด ๋๋‚˜๋ฉด MongoDB ์—ฐ๊ฒฐ์„ ์•ˆ์ „ํ•˜๊ฒŒ ์ข…๋ฃŒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. client.close() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ์„ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// MongoDB ์—ฐ๊ฒฐ ์ข…๋ฃŒ
await client.close();
console.log('MongoDB ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');

๊ฒฐ๋ก 

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Node.js์™€ MongoDB๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ $lookup ๋ฉ”์„œ๋“œ๋กœ ์ปฌ๋ ‰์…˜์„ ์กฐ์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. MongoDB์˜ $lookup์€ ์—ฌ๋Ÿฌ ์ปฌ๋ ‰์…˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ€์ด๋“œ๋ฅผ ํ†ตํ•ด MongoDB์—์„œ ํšจ์œจ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

๋Œ“๊ธ€ ์“ฐ๊ธฐ