안녕하세요

for문 data부르기 error는 try-catch로 넘어가기, bulkwrite 본문

유튜브컨텐츠탐색-StelLife/MongoDB

for문 data부르기 error는 try-catch로 넘어가기, bulkwrite

sakuraop 2023. 2. 25. 01:26

data를 불러올 때 예기치 못한 null과 undefined가 발생했다.

이유를 도무지 모르겠다. (db에 저장한 채널이 삭제되었기 때문으로 추정된다.)

50개의 요소 중 1개의 에러로 인해 함수가 멈추었기 때문에,

에러가 발생한 요소 1개는 errors collection을 만들어 저장하고,

나머지에 대해서는 이어서 처리하는 것이 유리하다 생각했다.

에러 콜렉션을 어떻게 작성하면 좋을지 몰라 문제되는 id를 저장시켰다.

 

이를 위해서 데이터를 제대로 불러오지 못해 에러가 발생하였을 경우에는

try-catch문과 for...of의 continue로 다음 요소부터 이어가도록 하였다.

스무번째 즈음에서 오류가 발생했지만 데이터를 저장한 모습.

 

app.get(
  "/api/playlistItems",
  wrapper(async (request, response) => {
    const channelsCollection = await db.collection("channels");
    const channelsData = await channelsCollection.find().toArray();
    const playlistsCollection = await db.collection("playlists");

    for (const { playlistId } of channelsData) {
      try {
        const playlistItems = await getPlaylistItems(playlistId);
        const videos = playlistItems?.items || [];
        const playlistUpdates = videos.map((playlistItem) => ({
          updateOne: {
            filter: { playlistId },
            update: {
              $set: {
                channelTitle: playlistItem.snippet.channelTitle,
                channelId: playlistItem.snippet.channelId,
              },
              $push: {
                videoArray: {
                  title: playlistItem.snippet.title,
                  videoId: playlistItem.snippet.resourceId.videoId,
                  description: playlistItem.snippet.description,
                  publishedAt: playlistItem.snippet.publishedAt,
                  thumbnailsUrl: playlistItem.snippet.thumbnails.high.url,
                },
              },
            },
            upsert: true,
          },
        }));
        await playlistsCollection.bulkWrite(playlistUpdates);
      } catch (error) {
        await db.collection("errors").updateOne(
          // {filter}, {update}, {upsert}
          { playlistId },
          { $set: { playlistId, addTime: new Date() }, $inc: { errorCount: 1 } },
          { upsert: true }
        );

        console.error(error, `playlistId: ${playlistId} 에러`);
      }
      console.log(`playlistId: ${playlistId} 업데이트 함`);
    }
    console.log("/api/playlistItems 접속");
  })
);

처음에는 forEach 함수를 이용하여 구현하려 했지만,

forEach()를 await 같이 써도 되지 않을까 생각하여 시도했지만 작동하지 않았다.

대신에 for..of 반복문을 사용하면 해결할 수 있었고,

 

forEach > for..of > for 순으로 많이 이용했지만  

for...of 의 장점이 훨씬 많다고 생각하게 되었다.

for..of는 iterable한 객체라면 어디에든 사용할 수 있고,

무엇보다 continue, break 가 가능하다.

 

지금까지는 forEach가 가장 편리하였기 때문에 가장 자주 이용하고 있었지만.

앞으로는 forEach는 index를 이용할 필요가 있을 경우에만 쓰고, 

 

for...of를 우선적으로 써야겠다고 생각하게 되었다.

코드를 병렬적으로 처리하여 성능 면에서도 for와 for...of가 좋다.

코드 가독성 면에서도 뛰어나 error를 찾기도 더 쉬워진다.


bulkwrite(): 배열에 저장된 메서드(updateOne과 같은)를 한 번에 처리하기

    for (const { playlistId } of channelsData) {
      try {
        const playlistItems = await getPlaylistItems(playlistId);
        const videos = playlistItems?.items || [];
        const playlistUpdates = videos.map((playlistItem) => ({
          updateOne: {
            filter: { playlistId },
            update: {
              $set: {
                channelTitle: playlistItem.snippet.channelTitle,
                channelId: playlistItem.snippet.channelId,
              },
              $push: {
                videoArray: {
                  title: playlistItem.snippet.title,
                  videoId: playlistItem.snippet.resourceId.videoId,
                  description: playlistItem.snippet.description,
                  publishedAt: playlistItem.snippet.publishedAt,
                  thumbnailsUrl: playlistItem.snippet.thumbnails.high.url,
                },
              },
            },
            upsert: true,
          },
        }));
        await playlistsCollection.bulkWrite(playlistUpdates);

bulkWirte() 메서드배열을 전달받습니다.

updateOne(), updateMany(), replaceOne(), deleteOne(), deleteMany() 등 

다양한 메서드를 포함하는 객체를 배열로 전달받아 한 번의 호출로 여러 개의 작업을 처리할 수 있습니다. 

 

위의 코드에서 배열은 [{updateOne}, {updateOne}, {updateOne}]과 같이 updateOne 프로퍼티를 다수 가지고 있습니다.

updateOne 프로퍼티는 updateOne() 메서드를 호출합니다.

updateOne() 메서드는 filter, update, usert 객체를 인자 받습니다.

update 객체는 $set, $push, $inc와 같은 update operator로 DB 작업을 수행합니다.

upsert 프로퍼티 true 일 때 존재하지 않는 프로퍼티를 새롭게 추가하게 됩니다.