(몽고DB 완벽 가이드) Chapter 3. 도큐먼트 생성, 갱신, 삭제

이재문·2023년 11월 27일
  • 도큐먼트 추가 및 삭제
  • 기존 도큐먼트 갱신
  • 연산 때 안정성, 속도 선택

3.1 - 도큐먼트 삽입 insertOne

> db.movies.insertOne({'title': '엘리멘탈'})
  • input값과 _id를 따로 입력 해 주지 않았으므로 _id 자동 생성

3.1.1 - insertMany

  • ex)
    • bulk_insert와 비슷

      > db.movides.insertMany([
      							{'title': '엘리멘탈'},
      							{'title': '오펜하이머'},
      							...
      ])
      
      >> {
        acknowledged: true,
        insertedIds: {
          '0': ObjectId("64eafa5d96a5c1d4ab0b5c36"),
          '1': ObjectId("64eafa5d96a5c1d4ab0b5c37")
        }
      }
      
      > db.movies.find()
      [
        { _id: ObjectId("64eafa5d96a5c1d4ab0b5c36"), title: '엘리멘탈' },
        { _id: ObjectId("64eafa5d96a5c1d4ab0b5c37"), title: '오펜하이머' }
      ]
  • insertMany는 단일 컬렉션에 다수의 도큐먼트를 삽입할 때 유용
  • 대량 data(file)를 삽입 할 수 있는 Mongoimport
  • 48MB보다 큰 데이터는 48MB로 분할 삽입

정렬 연산 / 비정렬 연산

  • 도큐먼트를 input한 순서대로 삽입되려면 orderedtrue로 지정하면 된다.(default) - 정렬 연산
  • 도큐먼트가 input한 순서대로 삽입 되지 않도록 하려면 orderedfalse로 지정하면 된다.(default) - 비정렬 연산
  • bulk_insert 도중에 에러가 발생
    • 정렬 연산 - 에러 발생 이후 삽입 X
    • 비정렬 연산 - 에러가 발생한 도큐먼트를 제외한 나머지 도큐먼트 삽입
    • ex)
      • 정렬 연산 _id 중복값 에러 발생
        > db.movies.insertMany([
        									{'_id':1, 'title': '엘리멘탈' }, 
        									{'_id':1, 'title': '오펜하이머'},
        									{'_id': 3, 'title': '미션임파서블'}
        ])
        
        // duplicate 에러 발생
        >> Uncaught:
        MongoBulkWriteError: E11000 duplicate key error collection: practice.movides index: _id_ dup key: { _id: 1 }
        Result: BulkWriteResult {
          **insertedCount: 1,**
          matchedCount: 0,
          modifiedCount: 0,
          deletedCount: 0,
          upsertedCount: 0,
          upsertedIds: {},
          insertedIds: { '0': 1, '1': 1, '2': 3 }
        }
        Write Errors: [
          WriteError {
            err: {
              index: 1,
              code: 11000,
              errmsg: 'E11000 duplicate key error collection: practice.movides index: _id_ dup key: { _id: 1 }',
              errInfo: undefined,
              op: { _id: 1, title: '오펜하이머' }
            }
          }
        ]
        
        > db.movies.find()
        // _id: 1 만 삽입 성공
        >>[ { _id: 1, title: '엘리멘탈' } ]
      • 비정렬 연산 _id 중복값 에러 발생
        > db.movides.insertMany([
        										{'_id':1, 'title': '엘리멘탈'},
        										{'_id':1, 'title': '오펜하이머'},
        										{'_id': 3, 'title': '미션임파서블'}
        									],
        								{'ordered':false}
        )
        
        // duplicate 에러 발생
        >> Uncaught:
        MongoBulkWriteError: E11000 duplicate key error collection: practice.movides index: _id_ dup key: { _id: 1 }
        Result: BulkWriteResult {
          **insertedCount: 2,**
          matchedCount: 0,
          modifiedCount: 0,
          deletedCount: 0,
          upsertedCount: 0,
          upsertedIds: {},
          insertedIds: { '0': 1, '1': 1, '2': 3 }
        }
        Write Errors: [
          WriteError {
            err: {
              index: 1,
              code: 11000,
              errmsg: 'E11000 duplicate key error collection: practice.movides index: _id_ dup key: { _id: 1 }',
              errInfo: undefined,
              op: { _id: 1, title: '오펜하이머' }
            }
          }
        ]
        
        > db.movies.find()
        // _id: 1, 3 성공
        >> [ { _id: 1, title: '엘리멘탈' }, { _id: 3, title: '미션임파서블' } ]

3.1.2 - 삽입 유효성 검사

  • mongoDB의 기본 유효성 검사
    • 도큐먼트의 기본 구조 검사
      • _id 필드 유/무 확인
      • 크기 검사 (16MB)

3.1.3 - 삽입

  • version 3.0 까지 insert 사용
  • version 3.0 이후 insertOne, insertMany 등 API 사용
  • ex).
    > db.movides.insert({'title': '엘리멘탈' })
    
    // Warning
    >> DeprecationWarning: Collection.insert() is deprecated. Use insertOne, insertMany, or bulkWrite.
    // insert 정상 작동
    {
      acknowledged: true,
      insertedIds: { '0': ObjectId("64eb0ab3d89754f67e60ae00") }
    }
    

3.2 - 도큐먼트 삭제

  • deleteOne, deleteMany
  • ex
    • deleteOne
      > db.movies.find()
      >> [
        { _id: 1, title: '엘리멘탈', month: 7 },
        { _id: 2, title: '오펜하이머', month: 7 },
        { _id: 3, title: '미션임파서블', month: 6 }
      ]
      
      > db.movies.deleteOne({'_id':1})
      >> { acknowledged: true, deletedCount: 1 }
      
      > db.movies.find()
      >> [
        { _id: 2, title: '오펜하이머', month: 7 },
        { _id: 3, title: '미션임파서블', month: 6 }
      ]
      
      ===
      
      > db.movies.find()
      >> [
        { _id: 1, title: '엘리멘탈', month: 7 },
        { _id: 2, title: '오펜하이머', month: 7 },
        { _id: 3, title: '미션임파서블', month: 6 }
      ]
      
      // month 7인 도큐먼트가 2개지만 deleteOne은 1개만 삭제
      > db.movies.deleteOne({'month': 7})
      >> { acknowledged: true, deletedCount: 1 }
      
      > db.movies.find()
      >> [
        { _id: 2, title: '오펜하이머', month: 7 },
        { _id: 3, title: '미션임파서블', month: 6 }
      ]
    • deleteMany
      > db.movies.find()
      >> [
        { _id: 1, title: '엘리멘탈', month: 7 },
        { _id: 2, title: '오펜하이머', month: 7 },
        { _id: 3, title: '미션임파서블', month: 6 }
      ]
      
      > db.movies.deleteMany({'month':7})
      >> { acknowledged: true, deletedCount: 2 }
      
      > db.movies.find()
      >> [ { _id: 3, title: '미션임파서블', month: 6 } ]
  • version 3.0 이전에 remove 메소드 사용
    • remove 지원되지만 Warning 발생

3.2.1 - drop

  • 컬렉션 삭제
  • drop된 document는 복구 X

3.3 - 도큐먼트 갱신

3.3 - 도큐먼트 갱신

  • updateOne, updateMany
    • 필터, 수정할 값(부분)을 매개변수로 받는다.
      updateOne('filter document', 'modifier document')
      updateMany('filter document', 'modifier document')
  • replaceOne
    • replaceOne도 비슷하다. 필터, 수정할 값을 매개변수로 받는다. - document 전체를 치환한다.
      db.movies.find()
      [ { _id: 3, title: '엘리멘탈', month: 3 } ] 
      > db.movies.find()
      >> [ { _id: 3, title: '미션임파서블', month: 6 } ]
      
      > db.movies.replaceOne({'_id': 3}, {'title': '엘리멘탈'})
      >> {
        acknowledged: true,
        insertedId: null,
        matchedCount: 1,
        modifiedCount: 1,
        upsertedCount: 0
      }
      
      > db.movies.find()
      >> [ { _id: 3, title: '엘리멘탈' } ]

3.3.2 - 갱신 연산자

  • update

  • $inc - 값 증가/감소 연산자 (+, -)

    • int, long, double, decimal 타입 값만 사용 가능

    • null, bool, str 사용 불가

      > db.movies.find()
      >> [ { _id: 3, title: '엘리멘탈', open: { month: 3 } } ]
      
      > db.movies.updateOne({"title":"엘리멘탈"},{"$inc":{"views":  1}})
      
      > db.movies.find()
      [ { _id: 3, title: '엘리멘탈', open: { month: 3 }, views: 1 } ]
      
      ---------------------------------------------------------------------
      
      > db.movies.find()
      >> [ { _id: 3, title: '엘리멘탈', month: 3, views: 3 } ]
      
      > db.movies.update({"title":"엘리멘탈"},{"$inc":{"views":1}})
      {
        acknowledged: true,
        insertedId: null,
        matchedCount: 1,
        modifiedCount: 1,
        upsertedCount: 0
      }
      
      > db.movies.find()
      >> [ { _id: 3, title: '엘리멘탈', month: 3, views: 4 } ]
      
      ---------------------------------------------------------------------
      
      > db.movies.find()
      [ { _id: 3, title: '엘리멘탈', open: { month: 3 }, views: 4 } ]
      
      > db.movies.updateOne({"title":"엘리멘탈"},{"$inc":{"views":  -2}})
      
      > db.movies.find()
      [ { _id: 3, title: '엘리멘탈', open: { month: 3 }, views: 2 } ]
  • $set - 데이터 추가 및 수정

    > db.movies.find()
    >>[ { _id: 3, title: '엘리멘탈', month: 3, views: 4 } ]
    
    > db.movies.updateOne({"title":"엘리멘탈"},{"$set":{"month":9}})
    >> {
      acknowledged: true,
      insertedId: null,
      matchedCount: 1,
      modifiedCount: 1,
      upsertedCount: 0
    }
    
    > db.movies.find()
    >> [ { _id: 3, title: '엘리멘탈', month: 9, views: 4 } ]
  • $unset - key, value 제거

    > db.movies.find()
    >>[ { _id: 3, title: '엘리멘탈', month: 9, views: 4 } ]
    
    > db.movies.updateOne({"title":"엘리멘탈"},{"$unset":{"month": 1}})
    >>{
      acknowledged: true,
      insertedId: null,
      matchedCount: 1,
      modifiedCount: 1,
      upsertedCount: 0
    }
    
    > db.movies.find()
    >> [ { _id: 3, title: '엘리멘탈', views: 4 } ]
  • $push - 배열에 쌓는 연산자

    > db.movies.find()
    >> [
      {
        _id: 3,
        title: '엘리멘탈',
        open: { month: 3 },
        views: 2,
        comment: [ { contents: '재미x' } ]
      }
    ]
    
    > db.movies.updateOne({"title":"엘리멘탈"},{"$push":{"comment":{"contents":"재미o"}}})
    
    > db.movies.find()
    >> [
      {
        _id: 3,
        title: '엘리멘탈',
        open: { month: 3 },
        views: 2,
        comment: [ { contents: '재미x' }, { contents: '재미o' } ]
      }
    ]
    
    ---------------------------------------------------------------------------
    
    db.movies.find()
    [
      {
        _id: 3,
        title: '엘리멘탈',
        open: { month: 3 },
        views: 2,
        comment: [ { contents: '재미x' }, { contents: '재미o' } ]
      }
    ]
    
    > db.movies.updateOne({"title":"엘리멘탈"},{"$push":{"comment":{"$each":[{"contents":"재미o"},{"contents":"재밍미징"}]}}})
    
    > db.movies.find()
    [
      {
        _id: 3,
        title: '엘리멘탈',
        open: { month: 3 },
        views: 2,
        comment: [
          { contents: '재미x' },
          { contents: '재미o' },
          { contents: '재미o' },
          { contents: '재밍미징' }
        ]
      }
    ]
    
    > db.movies.updateOne({"title":"엘리멘탈"},{"$push":{"comment":{"$each":[{"contents":"재미o"},{"contents":"재밍미징"}], "$slice": -5}}})
    
    // 5개 이상 X
    > db.movies.find()
    [
      {
        _id: 3,
        title: '엘리멘탈',
        open: { month: 3 },
        views: 2,
        comment: [
          { contents: '재미o' },
          { contents: '재미o' },
          { contents: '재밍미징' },
          { contents: '재미o' },
          { contents: '재밍미징' }
        ]
      }
    ]
  • $slice로 최대 저장 개수 제한 가능

  • $slice나 $sort를 $push와 함께 사용하려면 $each도 함께 사용해야 한다.

  • $addToSet - 중복 값 추가 X

    > db.User.find()
    [
      {
        _id: ObjectId("638deb3234a057cad223a0ce"),
        name: 'Jaemon',
        email: [ 'ajbj@naver.com', 'abc@naver.com', 'ddd@naver.com' ]
      }
    ]
    
    > db.User.updateOne({"name":"Jaemon"}, {"$addToSet": {"email":"abc@naver.com"}})
    > db.User.find()
    [
      {
        _id: ObjectId("638deb3234a057cad223a0ce"),
        name: 'Jaemon',
        email: [ 'ajbj@naver.com', 'abc@naver.com', 'ddd@naver.com' ]
      }
    ]
    
    > db.User.updateOne({"name":"Jaemon"}, {"$addToSet": {"email":"abc1@naver.com"}})
    
    > db.User.find()
    [
      {
        _id: ObjectId("638deb3234a057cad223a0ce"),
        name: 'Jaemon',
        email: [
          'ajbj@naver.com',
          'abc@naver.com',
          'ddd@naver.com',
          'abc1@naver.com'
        ]
      }
    ]
    • $addToSet과 $each를 결합해서 사용 가능
  • 요소 제거하기

    • $pop
      • key 배열의 인덱스에 일치하는 값을 제거
    • $pull
      • 배열 내 주어진 조건에 일치하는 값 제거
  • 배열의 위치 기반 변경

    • array 내 object 내 값 증가 가능
      > db.movies.find()
      >> [
        {
          _id: 3,
          title: '엘리멘탈',
          open: { month: 3 },
          views: 2,
          comment: [
            { contents: '재미o', views: 5 },
            { contents: '재미o', views: 3 },
            { contents: '재밍미징', views: 1},
            { contents: '재미o', views: 2 },
            { contents: '재밍미징', views: 6 }
          ]
        }
      ]
      
      > db.movies.updateOne({"title":"엘리멘탈"}, {"$inc": {"comment.0.views": 1}})
      																														 ㄴ index부분만 증가
      > db.movies.find()
      [
        {
          _id: 3,
          title: '엘리멘탈',
          open: { month: 3 },
          views: 2,
          comment: [
            { contents: '재미o', views: 6 },
            { contents: '재미o', views: 3 },
            { contents: '재밍미징', views: 1 },
            { contents: '재미o', views: 2 },
            { contents: '재밍미징', views: 6 }
          ]
        }
      ]

3.3.3 - 갱신 입력(upsert)

  • update 할 도큐먼트가 있으면 update, 없으면 새 도큐먼트 생성
  • {”upset” : true}
    db.movies.updateOne({"title":"엘리멘탈1"}, {"$inc": {"comment.2.views": 1}})
    {
      acknowledged: true,
      insertedId: null,
      matchedCount: 0,
      modifiedCount: 0,
      upsertedCount: 0
    }
    
    ------------------------------------------------------------------------
    
    > db.movies.updateOne({"title":"엘리멘탈2"}, {"$inc": {"comment.views": 1}}, {"upsert": true})
    
    [
      {
        _id: 3,
        title: '엘리멘탈',
        open: { month: 3 },
        views: 2,
        comment: [
          { contents: '재미o', views: 6 },
          { contents: '재미o', views: 3 },
          { contents: '재밍미징', views: 1 },
          { contents: '재미o', views: 3 },
          { contents: '재밍미징', views: 6 }
        ]
      },
      {
        _id: ObjectId("64ff12a20803fe720ebca357"),
        title: '엘리멘탈2',
        comment: { views: 1 }
      }
  • $setOnInsert

    • createdAt 도큐먼트가 삽입 될 때 입력
    • 패딩 생성, 카운터 초기화하는데 사용
    • ObjectId를 사용하지 않는 컬렉션에 유용
  • 저장 셀 보조자

    • save는 도큐먼트가 존재하지 않으면 도큐먼트를 삽입, 존재하면 도큐먼트를 갱신하게 하는 셀 함수
    • 셀 함수는 매개변수가 하나이고 도큐먼트를 넘겨받는다.
    • 도큐먼트가 "_id" 키를 포함하면 save는 갱신 입력을 실행하고 포함하지 않으면 삽입을 실행.
  • 다중 도큐먼트 갱신

    • 다중 스키마를 변경하거나 특정 타겟에게 새로운 정보를 추가할 때는 updateMany를 사용

3.3.5 - 갱신한 도큐먼트 반환

.... # before
update_result = client.admin_member.update_one({'_id': obj['_id']}, {'$set': params})
if is_return:
    return client.admin_member.find_one({'_id': obj['_id']})
return update_result

vs

.... # after
return client.admin_member.find_one_and_update({'_id': obj['_id']}, {'$set': params}, return_document=True)

# find_one_and_update
# returnNewDocument 없으면 update 이전 값 반환
# returnNewDocument로 update 이후 값을 반환 replace 동일
profile
이제부터 백엔드 개발자

0개의 댓글