1인 MongoDB University/M121 Aggregation Framework(3)

117555 단어 MongoDBtech
이 기록은 부가 달력 형식으로 시작된 몬godb University의 학습 과정의 기록입니다. 계속!

지금 코스.

  • M121: M121: The MongoDB Aggregation Framework
  • https://university.mongodb.com/mercury/M121/2021_March_16/overview
  • 이 노선에서 Aggregation의 깊이 있는 발굴을 진행한다.
    지난번 보도는1인 MongoDB University/M121 Aggregation Framework(2)였다.

    Chapter 2: Basic Aggregation - Utility Stages


    $addFields and how it is similar to $project


    영상 해설.aggregation에 사용되는 $addField.$project와 비슷하지만 출력 결과에 필드를 추가할 수 있을 뿐만 아니라 JSON 모드가 끼워 넣은 필드에도 추가할 수 있다
  • Ref. https://docs.mongodb.com/manual/reference/operator/aggregation/addFields/
  • GeoNer의 경우 어떻게 처리합니까?

    $geoNear 조작원은 지정된 위치에 가까운 데이터를 추출한다.이용할 때 파이프라인의 초기 단계만 2차원 지리 공간 인덱스가 필요하고 몇 가지 필요한 매개 변수 등이 있다.출력은 지정된 위치와의 거리를 늘릴 수 있습니다
  • 기본값id 필드는 12바이트 객체의 ID입니다(숫자).
  • 에서 출력 결과를 덮어쓸 수 있습니다.
  • 예: $addField: "$item"} 결과 확인 시id 필드 확인 필요
  • Ref. https://docs.mongodb.com/manual/reference/operator/aggregation/geoNear/?jmp=university
  • 
    // 一件ためしに取り出し
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.nycFacilities.findOne()
    {
            "_id" : ObjectId("59a57f72ea2da4c51ef35c52"),
            "name" : "Owl Hollow Park",
            "address" : {
                    "number" : "",
                    "street" : "",
                    "city" : "Staten Island",
                    "zipcode" : "10312"
            },
            "borough" : "Staten Island",
            "location" : {
                    "type" : "Point",
                    "coordinates" : [
                            -74.196784,
                            40.561112
                    ]
            },
            "domain" : "Parks, Gardens, and Historical Sites",
            "group" : "Parks and Plazas",
            "specialty" : "Parks",
            "type" : "Park"
    }
    

    Utility Stages / Cursor-like stages: Part 1


    find ()에서도 사용할 수 있는order,limit,sort,sample 등 함수입니다.
    먼저 샘플 DB에 연결합니다.
    // MongoDB Atlasのクラスタから
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> show databases
    100YWeatherSmall  0.128GB
    admin             0.000GB
    aggregations      0.068GB
    citibike          0.367GB
    city              0.002GB
    config            0.015GB
    coursera-agg      0.083GB
    feedback          0.000GB
    local             0.710GB
    mflix             0.449GB
    results           0.000GB
    ships             0.001GB
    video             0.513GB
    
    // show databases, use databasename あたりはMySQLあたりと一緒ですね!
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> use aggregations
    switched to db aggregations
    
    // tableではなくてcollectionになるので、一覧表示
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> show collections
    air_airlines
    air_alliances
    air_routes
    bronze_banking
    child_reference
    customers
    employees
    exoplanets
    gold_banking
    icecream_data
    movies
    nycFacilities
    parent_reference
    silver_banking
    solarSystem
    stocks
    system.profile
    

    find 사용


    이번에 사용하기$addFields 소장.
    우선aggregation이 아니라find() 추출열을 사용합니다.
    // 件数確認:太陽系の星は9つ
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.solarSystem.find().count()
    9
    
    // ``numberOfMoons`` and ``name`` フィールドを指定して取り出します
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.solarSystem.find({}, {"_id": 0, "name": 1, "numberOfMoons": 1}).pretty();
    { "name" : "Earth", "numberOfMoons" : 1 }
    { "name" : "Neptune", "numberOfMoons" : 14 }
    { "name" : "Uranus", "numberOfMoons" : 27 }
    { "name" : "Saturn", "numberOfMoons" : 62 }
    { "name" : "Jupiter", "numberOfMoons" : 67 }
    { "name" : "Venus", "numberOfMoons" : 0 }
    { "name" : "Mercury", "numberOfMoons" : 0 }
    { "name" : "Sun", "numberOfMoons" : 0 }
    { "name" : "Mars", "numberOfMoons" : 2 }
    
    // skip(N)で、最初の5件を飛ばします(オーダーは登録順)
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.solarSystem.find({}, {"_id": 0, "name": 1, "numberOfMoons": 1}).skip(5).pretty()
    { "name" : "Venus", "numberOfMoons" : 0 }
    { "name" : "Mercury", "numberOfMoons" : 0 }
    { "name" : "Sun", "numberOfMoons" : 0 }
    { "name" : "Mars", "numberOfMoons" : 2 }
    
    // limit(N)で、N件のみ抽出(オーダーは登録順)skipで飛ばされたのと同じものが返ります
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.solarSystem.find({}, {"_id": 0, "name": 1, "numberOfMoons": 1}).limit(5).pretty();
    
    { "name" : "Earth", "numberOfMoons" : 1 }
    { "name" : "Neptune", "numberOfMoons" : 14 }
    { "name" : "Uranus", "numberOfMoons" : 27 }
    { "name" : "Saturn", "numberOfMoons" : 62 }
    { "name" : "Jupiter", "numberOfMoons" : 67 }
    
    // sortをかけます
    // ソートのキーはnumberOfMoons(衛星の数)の降順で
    db.solarSystem.find({}, { "_id": 0, "name": 1, "numberOfMoons": 1 }).sort( {"numberOfMoons": -1 } ).pretty();
    
    { "name" : "Jupiter", "numberOfMoons" : 67 }
    { "name" : "Saturn", "numberOfMoons" : 62 }
    { "name" : "Uranus", "numberOfMoons" : 27 }
    { "name" : "Neptune", "numberOfMoons" : 14 }
    { "name" : "Mars", "numberOfMoons" : 2 }
    { "name" : "Earth", "numberOfMoons" : 1 }
    { "name" : "Venus", "numberOfMoons" : 0 }
    { "name" : "Mercury", "numberOfMoons" : 0 }
    { "name" : "Sun", "numberOfMoons" : 0 }
    

    aggregation 무대에서 사용


    // ``$limit``
    db.solarSystem.aggregate([
      {
        "$project": {
          "_id": 0,
          "name": 1,
          "numberOfMoons": 1
        }
      },
      { "$limit": 5  }
    ]).pretty();
    
    { "name" : "Earth", "numberOfMoons" : 1 }
    { "name" : "Neptune", "numberOfMoons" : 14 }
    { "name" : "Uranus", "numberOfMoons" : 27 }
    { "name" : "Saturn", "numberOfMoons" : 62 }
    { "name" : "Jupiter", "numberOfMoons" : 67 }
    
    // skip
    db.solarSystem.aggregate([
      {
        "$project": {
          "_id": 0,
          "name": 1,
          "numberOfMoons": 1
        }
      },
      {
        "$skip": 1
      }
    ]).pretty()
    
    // 1つだけスキップ
    { "name" : "Neptune", "numberOfMoons" : 14 }
    { "name" : "Uranus", "numberOfMoons" : 27 }
    { "name" : "Saturn", "numberOfMoons" : 62 }
    { "name" : "Jupiter", "numberOfMoons" : 67 }
    { "name" : "Venus", "numberOfMoons" : 0 }
    { "name" : "Mercury", "numberOfMoons" : 0 }
    { "name" : "Sun", "numberOfMoons" : 0 }
    { "name" : "Mars", "numberOfMoons" : 2 }
    
    // COUNTにフィールド名を指定して出力
    // "terrestrial planets": N
    db.solarSystem.aggregate([{
      "$match": {
        "type": "Terrestrial planet"
      }
    }, {
      "$project": {
        "_id": 0,
        "name": 1,
        "numberOfMoons": 1
      }
    }, {
      "$count": "terrestrial planets"
    }]).pretty();
    
    { "terrestrial planets" : 4 }
    
    /*
    // 地球型
    { "name" : "Earth", "numberOfMoons" : 1 }
    { "name" : "Venus", "numberOfMoons" : 0 }
    { "name" : "Mercury", "numberOfMoons" : 0 }
    { "name" : "Mars", "numberOfMoons" : 2 }
    */
    
    // sort
    // ``$sort`` stage
    db.solarSystem.aggregate([{
      "$project": {
        "_id": 0,
        "name": 1,
        "numberOfMoons": 1
      }
    }, {
      "$sort": { "numberOfMoons": -1 }
    }]).pretty();
    
    { "name" : "Jupiter", "numberOfMoons" : 67 }
    { "name" : "Saturn", "numberOfMoons" : 62 }
    { "name" : "Uranus", "numberOfMoons" : 27 }
    { "name" : "Neptune", "numberOfMoons" : 14 }
    { "name" : "Mars", "numberOfMoons" : 2 }
    { "name" : "Earth", "numberOfMoons" : 1 }
    { "name" : "Venus", "numberOfMoons" : 0 }
    { "name" : "Mercury", "numberOfMoons" : 0 }
    { "name" : "Sun", "numberOfMoons" : 0 }
    
    
    // setting ``allowDiskUse`` option
    // hasMagneticField -> 磁場があるかないか
    db.solarSystem.aggregate([{
      "$project": {
        "_id": 0,
        "name": 1,
        "hasMagneticField": 1,
        "numberOfMoons": 1
      }
    }, {
      "$sort": { "hasMagneticField": -1, "numberOfMoons": -1 }
    }], { "allowDiskUse": true }).pretty();
    
    // 火星と金星は固有の磁場がない....!
    { "name" : "Jupiter", "numberOfMoons" : 67, "hasMagneticField" : true }
    { "name" : "Saturn", "numberOfMoons" : 62, "hasMagneticField" : true }
    { "name" : "Uranus", "numberOfMoons" : 27, "hasMagneticField" : true }
    { "name" : "Neptune", "numberOfMoons" : 14, "hasMagneticField" : true }
    { "name" : "Earth", "numberOfMoons" : 1, "hasMagneticField" : true }
    { "name" : "Mercury", "numberOfMoons" : 0, "hasMagneticField" : true }
    { "name" : "Sun", "numberOfMoons" : 0, "hasMagneticField" : true }
    { "name" : "Mars", "numberOfMoons" : 2, "hasMagneticField" : false }
    { "name" : "Venus", "numberOfMoons" : 0, "hasMagneticField" : false }
    

    Utility Stages / Cursor-like stages: $sample Stage

    solarSystem 많은 문서의 모음에서 데이터를 얻다
    랜덤으로 뽑고 싶을 때 편해!
    Ref. https://docs.mongodb.com/manual/reference/operator/aggregation/sample/
    If all the following conditions are met, $sample uses a pseudo-random cursor to select documents:
    
    $sample is the first stage of the pipeline
    N is less than 5% of the total documents in the collection
    The collection contains more than 100 documents
    
    다음 조건에 해당하면 위조 커서를 사용하여 문서를 추출합니다.
  • $sample 파이프의 첫 번째 레벨
  • 에 사용
  • N은 전체 건수의 5% 미만
  • 모음에 100개 이상의 문서가 있음
  • 설령 한 가지 조건이 상술한 조건에 부합되지 않더라도sort의 제약과 같은 조건에 따라 무작위로 데이터를 추출할 수 있다.
    MongoDB의$sample는 100MB의 메모리 내 제한이 있다.
    기본적으로 100MB 이상 정렬하면 오류가 발생합니다!
    Ref. https://docs.mongodb.com/manual/reference/operator/aggregation/sort/#std-label-sort-memory-limit
    대량의 데이터를 정렬해야 할 경우 $sort 옵션을 지정하여 이 제한을 취소하십시오.
    ※ aggregation의 allow Diskusage 옵션
  • 사용 시 allowDiskUse 하위 디렉토리
  • 사용
  • MongoDB4.2에서 메모리의 제한을 초과하여 디스크를 사용했을 때 상세한 로그, 진단 로그에 이 정보를 기록한다
  • Optional. Enables writing to temporary files. When set to true,
    aggregation operations can write data to the _tmp subdirectory in the
    dbPath directory. See Perform Large Sort Operation with External Sort
    for an example.
    
    Starting in MongoDB 4.2, the profiler log messages and diagnostic log
    messages includes a usedDisk indicator if any aggregation stage wrote
    data to temporary files due to memory restrictions.
    

    Chapter 2: Basic Aggregation / Lab: Using Cursor-like Stages


    연습 문제.
    Problem
    영화 개봉 당시 직원들은 설문조사를 했다.
    좋아하는 배우에 대한 조사 결과는 다음과 같다.
    미국(USA)에서 개봉한 영화, 토마토토스.viewer.rating이 3개 이상의 물건을 꺼내 새로운 영역(num favs)으로 이 같은 인기 배우가 영화에 얼마나 많이 등장했는지 보여주세요.
    그리고favs와tomatoes.viewer.rating, 제목의 값에 따라 정렬하십시오.내림차순으로 표시하십시오.
    이 결과 25번 영화의 제목은 무엇입니까?
    대답하다.
    favorites = [
      "Sandra Bullock",
      "Tom Hanks",
      "Julia Roberts",
      "Kevin Spacey",
      "George Clooney"]
    

    Chapter 2: Basic Aggregation / Lab: Bringing it all together


    연습 문제.
    Problem
    
    // 件数を確認
    MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.movies.count()
    44488
    
    // タイトルが欲しい
    db.movies.aggregate([
      {
        $project: { _id:1, title: 1 }
      },
      { $limit: 2 }
    ])
    
    // お試し
    { "_id" : ObjectId("573a1390f29313caabcd4cf1"), "title" : "Ingeborg Holm" }
    { "_id" : ObjectId("573a1390f29313caabcd4136"), "title" : "Pauvre Pierrot" }
    
    // tomatoes があるものだけ取り出す
    // tomatoes: { $exists: true }
    db.movies.aggregate([
      { $match: { tomatoes: { $exists: true } } },
      {
        $project: { _id:1, title: 1, tomatoes: 1 }
      },
      { $limit: 2 }
    ]).pretty()
    
    // 結果があるものを確認
    {
     "_id" : ObjectId("573a1390f29313caabcd421c"),
     "title" : "A Turn of the Century Illusionist",
     "tomatoes" : {
      "viewer" : {
       "rating" : 3.8,
       "numReviews" : 32
      },
      "lastUpdated" : ISODate("2015-08-20T18:46:44Z")
     }
    }
    {
     "_id" : ObjectId("573a1390f29313caabcd4192"),
     "title" : "The Conjuring of a Woman at the House of Robert Houdin",
     "tomatoes" : {
      "viewer" : {
       "rating" : 3.7,
       "numReviews" : 59
      },
      "lastUpdated" : ISODate("2015-09-11T17:46:29Z")
     }
    }
    
    // まずtomatoes がある and tomatoes.viewer.rating >= 3
    db.movies.aggregate([
      {
        $match: { $and: [
          { tomatoes: { $exists: true } },
          { "tomatoes.viewer.rating": { $gte: 3 } }
        ]}
      },
      {
        $project: {
          _id:1, title: 1, tomatoes: 1
          }
      },
      { $limit: 5 }
    ]).pretty()
    
    // 新しいフィールド(num_favs)として、上記の人気俳優が映画の中に何人
    // 出てきたかを表示
    // $setIntersection で一致する要素を取り出して、数をカウントする
    
    // num_favsとtomatoes.viewer.rating、タイトルの値をもとにソートしてく
    // ださい。降順で表示
    db.movies.aggregate([
      {
        $match: { $and: [
          { tomatoes: { $exists: true } },
          { "tomatoes.viewer.rating": { $gte: 3 } },
          { cast: { $elemMatch: { $exists: true } } }
        ]}
      },
      {
        $project: {
          _id:1,
          title: 1,
          viewer_rating: "$tomatoes.viewer.rating",
          cast: 1,
          favs: {
            $setIntersection: [ "$cast", favorites ]
          },
        }
      },
      {
        $addFields: {
          num_favs: { $size: "$favs" }
        }
      },
      {
      "$sort": { "num_favs": -1, viewer_rating: -1, "title": -1  }
      },
      { $limit: 3 }
    ]).pretty()
    
    // 3件サンプリング
    {
     "_id" : ObjectId("573a13cbf29313caabd808d2"),
     "title" : "Gravity",
     "cast" : [
      "Sandra Bullock",
      "Orto Ignatiussen",
      "Ed Harris",
      "George Clooney"
     ],
     "viewer_rating" : 4,
     "favs" : [
      "George Clooney",
      "Sandra Bullock"
     ],
     "num_favs" : 2
    }
    {
     "_id" : ObjectId("573a139af29313caabcf0480"),
     "title" : "A Time to Kill",
     "cast" : [
      "Matthew McConaughey",
      "Sandra Bullock",
      "Samuel L. Jackson",
      "Kevin Spacey"
     ],
     "viewer_rating" : 3.6,
     "favs" : [
      "Kevin Spacey",
      "Sandra Bullock"
     ],
     "num_favs" : 2
    }
    {
     "_id" : ObjectId("573a13b5f29313caabd447ca"),
     "title" : "Extremely Loud & Incredibly Close",
     "cast" : [
      "Tom Hanks",
      "Thomas Horn",
      "Sandra Bullock",
      "Zoe Caldwell"
     ],
     "viewer_rating" : 3.5,
     "favs" : [
      "Sandra Bullock",
      "Tom Hanks"
     ],
     "num_favs" : 2
    }
    // num_favsとtomatoes.viewer.rating、タイトルの値をもとにソート
    
    
    db.movies.aggregate([
      {
        $match: { $and: [
          { tomatoes: { $exists: true } },
          { "tomatoes.viewer.rating": { $gte: 3 } },
          { cast: { $elemMatch: { $exists: true } } }
        ]}
      },
      {
        $project: {
          _id:1,
          title: 1,
          viewer_rating: "$tomatoes.viewer.rating",
          cast: 1,
          favs: {
            $setIntersection: [ "$cast", favorites ]
          },
        }
      },
      {
        $addFields: {
          num_favs: { $size: "$favs" }
        }
      },
      {
      "$sort": { "num_favs": -1, viewer_rating: -1, "title": -1  }
      },
      {
      "$count": "title"
    }
    ])
    
    { "title" : 27654 }
    
    
    // What is the title of the 25th film in the aggregation result?
    // N番目は?24件をスキップするといいのかな
    db.movies.aggregate([
      {
        $match: { $and: [
          { tomatoes: { $exists: true } },
          { "tomatoes.viewer.rating": { $gte: 3 } },
          { cast: { $elemMatch: { $exists: true } } }
        ]}
      },
      {
        $project: {
          _id:1,
          title: 1,
          viewer_rating: "$tomatoes.viewer.rating",
          cast: 1,
          favs: {
            $setIntersection: [ "$cast", favorites ]
          },
        }
      },
      {
        $addFields: {
          num_favs: { $size: "$favs" }
        }
      },
      {
        $sort: { "num_favs": -1, viewer_rating: -1, "title": -1  }
      },
      {
        $skip: 24
      },
      {
        $limit: 2
      }
    ]).pretty()
    
    
    {
     "_id" : ObjectId("573a13b2f29313caabd39eef"),
     "title" : "Fantastic Mr. Fox",
     "cast" : [
      "George Clooney",
      "Meryl Streep",
      "Jason Schwartzman",
      "Bill Murray"
     ],
     "viewer_rating" : 3.9,
     "favs" : [
      "George Clooney"
     ],
     "num_favs" : 1
    }
    {
     "_id" : ObjectId("573a13ddf29313caabdb320f"),
     "title" : "The Heat",
     "cast" : [
      "Sandra Bullock",
      "Melissa McCarthy",
      "Demian Bichir",
      "Marlon Wayans"
     ],
     "viewer_rating" : 3.8,
     "favs" : [
      "Sandra Bullock"
     ],
     "num_favs" : 1
    }
    
    // さらに条件:countriesにUSAのもの
    // 配列に $in を利用
    db.movies.aggregate([
      {
        $match: { $and: [
          { tomatoes: { $exists: true } },
          { "tomatoes.viewer.rating": { $gte: 3 } },
          { cast: { $elemMatch: { $exists: true } } },
          { countries: { $in: [ "USA" ] } }
        ]}
      },
      {
        $project: {
          _id:1,
          title: 1,
          viewer_rating: "$tomatoes.viewer.rating",
          cast: 1,
          favs: {
            $setIntersection: [ "$cast", favorites ]
          },
        }
      },
      {
        $addFields: {
          num_favs: { $size: "$favs" }
        }
      },
      {
        $sort: { "num_favs": -1, viewer_rating: -1, "title": -1  }
      },
      {
        $skip: 24
      },
      {
        $limit: 1
      },
      {
        $project: { _id: 0, title: 1 }
      }
    ]).pretty()
    
    // これが正解!
    { "title" : "The Heat" }
    
  • English
  • imdb.rating의 최소값은 1 이상
  • imdb.votes의 최소값은 1 이상
  • 공개 시점은 1990년 이후
  • votes를 정규화하고 축소 조정!
  • ※ 확대와 관련해서는 정규화 후 1부터 10까지 범위를 전환합니다.
    (이런 식으로 계산해! 링크에 이런 말이 있으니 이 방법으로 계산한다)
    //general scaling
    //1부터 10까지의 크기 조정 비율은 다음과 같다.
    //1+(1-10)(귀일화 값)
    min + (max - min) ((x - x_min)/(x_max - x_min))
    Calculate an average rating for each movie in our collection
    where English is an available language,
    the minimum imdb.rating is at least 1, the minimum imdb.votes is at
    least 1, and it was released in 1990 or after. You'll be required to
    rescale (or normalize) imdb.votes. The formula to rescale imdb.votes
    and calculate normalized_rating is included as a handout.
    
    What film has the lowest normalized_rating?
    
    이번_tmp의 결과도 마찬가지다. $addFields의 단계 처리와 달리 $project에서 필드를 사용하여 연산을 하는 경우 전 단계의 결과에 이 필드를 포함해야 한다는 점에 주의해야 한다.
    다음 처리에서 이전 $addFields 의 대상인 필드에 'imdb.votes' 가 포함되지 않으면 계산 결과가 비어 있음을 주의하십시오.
    // まずサンプリング:この条件
    /*
          { "imdb.rating": { $gte: 1 } },
          { "imdb.votes": { $gte: 1 } },
          { released: { $gte: 1990 } },
    */
    db.movies.aggregate([
      {
        $match: { $and: [
          { languages: { $in: [ "English" ] } },
          { "imdb.rating": { $gte: 1 } },
          { "imdb.votes": { $gte: 1 } },
          { released: { $gte: ISODate("1990-01-01") } },
        ]}
      },
      {
        $project: {
          _id:1,
          title: 1,
          "imdb.rating": 1,
          "imdb.votes": 1,
          released: 1
        }
      }
    ])
    
    /*
    以下の数を使ってね!
    x_max = 1521105
    x_min = 5
    min = 1
    max = 10
    x = "imdb.votes"
    
    x_new = (x - x_min) / (x_max - x_min)
    
    { $subtract: ["$imdb.votes", 5] } => (x - x_min) に該当
    { $subtract: [1521105, 5] } => (x_max - x_min) に該当
    
    $divideなので、割り算。(x - x_min) / (x_max - x_min) に該当
    
    $divide: [
      { $subtract: ["$imdb.votes", 5] },
      { $subtract: [1521105, 5] }
    ]
    
    上記で出した正規化した値に対し、9倍して1を足す
    正規化した値は0 - 1の範囲なのだけれど、この値を1 - 10 の範囲にスケールしなおすため。
    0 -> 1を起点に
    1 -> 10までに
    
    1. $projectのステージで計算
    */
    db.movies.aggregate([
      {
        $match: { $and: [
          { languages: { $in: [ "English" ] } },
          { "imdb.rating": { $gte: 1 } },
          { "imdb.votes": { $gte: 1 } },
          { released: { $gte: ISODate("1990-01-01") } },
        ]}
      },
      {
        $project: {
          _id:1,
          title: 1,
          normalized_value: {
            $divide: [
              { $subtract: ["$imdb.votes", 5] },
              { $subtract: [1521105, 5] }
            ]
          },
          "normalized_scaled_value": {
            $add: [
              1,
              { $multiply: [
                  9,
                  { $divide:
                    [
                      { $subtract: ["$imdb.votes", 5] },
                       { $subtract: [1521105, 5] }
                    ]
                  }
                ]
              }
            ]
          },
          "normalized_rating": {
            $avg: [ "$imdb.rating", {
                $add: [
                  1, { $multiply: [ 9, "$normalized_value" ] }
                ]
              }
            ]
          }
        }
      },
      { $sort: { "normalized_rating": 1 } },
      { $limit: 1 }
    ]).pretty()
    
    {
     "_id" : ObjectId("573a13ccf29313caabd837cb"),
     "title" : "The Christmas Tree",
     "normalized_value" : 0.00017027151403589506,
     "normalized_scaled_value" : 1.001532443626323,
     "normalized_rating" : 1.1
    }
    
    // "title" : "The Christmas Tree" が答え
    
    /*
    2. $projectの箇所ではとても長いので、$addFieldsに切り出してみる
    */
    db.movies.aggregate([
      {
        $match: { $and: [
          { languages: { $in: [ "English" ] } },
          { "imdb.rating": { $gte: 1 } },
          { "imdb.votes": { $gte: 1 } },
          { released: { $gte: ISODate("1990-01-01") } },
        ]}
      },
      {
        $project: {
          _id:1,
          title: 1,
          "imdb.votes": 1,
          "imdb.rating": 1,
          normalized_value: {
            $divide: [
              { $subtract: ["$imdb.votes", 5] },
              { $subtract: [1521105, 5] }
            ]
          }
        }
      },
      {
        $addFields: {
          "normalized_scaled_value": {
            $add: [
              1,
              { $multiply: [
                  9,
                  { $divide:
                    [
                      { $subtract: ["$imdb.votes", 5] },
                       { $subtract: [1521105, 5] }
                    ]
                  }
                ]
              }
            ]
          },
          "normalized_rating": {
            $avg: [
              "$imdb.rating",
              {
                $add: [
                  1, { $multiply: [ 9, "$normalized_value" ] }
                ]
              }
            ]
          }
        }
      },
      { $sort: { "normalized_rating": 1 } },
      { $limit: 1 }
    ]).pretty()
    
    // 結果は同じ"The Christmas Tree"
    {
     "_id" : ObjectId("573a13ccf29313caabd837cb"),
     "title" : "The Christmas Tree",
     "imdb" : {
      "rating" : 1.1,
      "votes" : 264
     },
     "normalized_value" : 0.00017027151403589506,
     "normalized_scaled_value" : 1.001532443626323,
     "normalized_rating" : 1.0507662218131615
    }
    

    이번 노트


    나는 점점 aggregation () 의 쓰기에 익숙해졌지만, 복잡한 상담은 시간이 필요하다.
    또 참고를 보면서 잘못을 생각하면 정말 큰일이다!
    위의 문제는 정규화 처리가 들어가 있어 더 못하는 내용이다.
    그럼 대충 풀어보니 문득 Mongodb Compoass를 사용해 봤던 게 생각납니다.
    이 프로그램은 처음에는 다양한 탭이 있는데 뭔지 모르겠지만, aggregation의 노선을 추진해 보았다. "아, 이거야!"이런 기능.
    MongoDB Compoass에aggregation용 라벨이 있어 각 관문에 조회를 작성하고 미리 보기를 섞으면서 데이터가 어떻게 추출되는지 변환되는지 확인할 수 있습니다!

    이번 결과도 잘 나왔다.
    아주 편리하군요!
    다음은 Chapter3, 집합 함수를 조작하는 조작원입니다.

    좋은 웹페이지 즐겨찾기