nodejsはlodashを通じて合併してunixtimeとDateからなる二つの配列を重なります.

8156 ワード

1.問題の起源
最近APIが実装されていますが、一部の機能は、Dateオブジェクトからなる配列をMongodbから取り出して、クライアントから送られてきたunixtimeをこの配列に統合し、繰り返していく必要があります.
例えば、モンスターgodbから取ったデータの中にgamingという項目があると仮定して、ユーザーがゲームに入る開始時間と終了時間を記録します.モングースのschemaの定義は大体このようになります.
const DeviceLogSchema = new Schema({
 ...
  gaming: [{ enter: Date, exit: Date, _id: false }],          
 ... 
});
mongodbから取ってきたデータは大体このようです.
{
"gaming": [
      {
        "enter": 2017-04-25T14:32:12.081Z,
        "exit": 2017-04-25T14:48:52.082Z,
      },
      {
        "enter": 2017-04-26T14:32:12.081Z,
        "exit": 2017-04-26T14:48:52.082Z,
      }
    ],
}
つまり、mogoogleのmodelで取り戻した記録では、enterとexitは共にDate(mongodbにとって)タイプであり、jsにとってはObject(jsはすべての単純タイプ以外のデータタイプをObjectに処理する)である.
let deviceLog = await DeviceLog.findOne({});
console.log(typeof deviceLog.enter) // ->Object
クライアントは、時間ごとにアプリを呼び出して、新しいユーザのゲーム時間をサーバに返信しますが、使うフォーマットはunixtimeです.
{
    "gaming": [{
      "enter": 1493130733081,
      "exit": 1493131734082,
    },{
      "enter": 1493130735084,
      "exit": 1493131736087,
    }],
}
ここのenterとexitのunixtimeタイムフォーマットは、jsにとってnumberタイプです.
私たちはmongoogleで保存する場合、unixtimeを任意に変換して直接保存する必要はありません.mongoogleはそれを自動的にDate形式に変えて保存します.つまり、保存前のgamingの内容は次のようになります.
"gaming": [
      {
        "enter": 2017-04-25T14:32:12.081Z,
        "exit": 2017-04-25T14:48:52.082Z,
      },
      {
        "enter": 2017-04-26T14:32:12.081Z,
        "exit": 2017-04-26T14:48:52.082Z,
      },
      {
        "enter": 1493130733081,
        "exit": 1493131734082,
      },
      {
        "enter": 1493130735084,
        "exit": 1493131736087,
      }
    ],
では、momodelで保存すると、自動的に以下のようなフォーマットになります.
"gaming": [
      {
        "enter": 2017-04-25T14:32:12.081Z,
        "exit": 2017-04-25T14:48:52.082Z,
      },
      {
        "enter": 2017-04-26T14:32:12.081Z,
        "exit": 2017-04-26T14:48:52.082Z,
      },
      {
        "enter": 2017-04-27T14:22:12.021Z,
        "exit": 2017-04-27T15:32:12.031Z,
      },
      {
        "enter": 2017-04-26T16:22:12.082Z,
        "exit": 2017-04-26T16:52:12.082Z,
      }
    ],
ここで解決する問題は:
  • は、クライアントからの新しい配列と、mongodbからフェッチされた配列をどのように統合しますか?
  • 合併時、どうやってゲームが入る時間enterによって繰り返しますか?
    もちろん、元の方法で2つの異なる配列をそれぞれ便利にして、データの種類を別のデータに変換して、同じかどうかを比較して、同じなら削除します.待ちたくないなら、データを配列に追加します.
    しかし、このような効率はあまりにも低いので、もっと優雅な方法があります.この問題を解決するのを助けてくれるはずです.
    2.実験データ
    私たちは上記の問題に基づいて、二つの実験用のデータを作成します.一つはmongodbから取ってきたデータです.
    const orgGaming = [
          {
            "enter": new Date("2017-04-25T14:32:12.081Z"),
            "exit": new Date("2017-04-25T14:48:52.082Z"),
          },
          {
            "enter": new Date("2017-04-26T14:32:12.081Z"),
            "exit": new Date("2017-04-26T14:48:52.082Z"),
          }
    ]
    
    一つはクライアントからのデータです.
    const newGaming = [
         {
            "enter": 1493130732081, //   orgGamine       
            "exit": 1493131732082, //   orgGamine       
          },
          {
            "enter": 1493130735084,
            "exit": 1493131736087,
          }
        ]
    
    新しい配列の中の第一のデータとenterとデータベースの中の第一のデータのenterは事実上同じです.だから私達は統合後のこの重複データは削除したいです.
    3.ES 6配列統合の新しい特性
    実は、繰り返される問題を考慮しなければ、ES 6の新しい特性によって完全に完成できます.
    array1.push(...array2)
    
    ここの'…'操作子は拡張演算子と呼ばれ、ES 6が導入した新しい特性です.目的は、1つの配列をカンマで区切られたパラメータ系列に散布することです.
    const array = [1, 2];
    console.log(...array); //     console.log(1,2)
    
    したがって、上記の例示的なコードの意味は、array 2をばらばらにした後、各要素をパラメータpushとしてarray 1に新しい配列を生成するということです.だから、私たちのシーンに応用すれば
    const orgGaming = [
          {
            "enter": new Date("2017-04-25T14:32:12.081Z"),
            "exit": new Date("2017-04-25T14:48:52.082Z"),
          },
          {
            "enter": new Date("2017-04-26T14:32:12.081Z"),
            "exit": new Date("2017-04-26T14:48:52.082Z"),
          }
    ]
    
    const newGaming = [
         {
            "enter": 1493130732081,
            "exit": 1493131732082,
          },
          {
            "enter": 1493130735084,
            "exit": 1493131736087,
          }
    ]
    
    orgGaming.push(...newGaming);
    console.log(orgGaming);
    
    最終的には重複していない結果を出力します.
    [ 
      { enter: 2017-04-25T14:32:12.081Z,
        exit: 2017-04-25T14:48:52.082Z },
      { enter: 2017-04-26T14:32:12.081Z,
        exit: 2017-04-26T14:48:52.082Z },
      { enter: 1493130732081, 
        exit: 1493131732082 },
      { enter: 1493130735084, 
        exit: 1493131736087 } 
    ]
    
    もちろん、ES 6のこの配列結合方式は、こうも書くことができる.
    [...array1,...array2]
    
    また、ES 6は、簡単なデータタイプを反復する方法を提供する.
    [...new Set([...array1 ,...array2])];
    
    しかし、これは単純なデータタイプに対してのみ繰り返します.例えば、数字タイプや文字列タイプなどです.
    const array1 = ['techgogogo', 'sina', 'baidu'];
    const array2 = ['techgogogo', 'google'];
    console.log([... new Set([...array1, ...array2])]);
    
    最後の出力:
    [ 'techgogogo', 'sina', 'baidu', 'google' ]
    
    しかし、ここのオブジェクトの種類からなる行列には無理です.
    最も重要なのは、compratorのフィードバック方法を提供していませんでした.私たちが処理するにはどうすればいいですか?2つのデータは重複していますか?
    ここで、lodashの配列操作は正しい解決策かもしれません.
    4.lodashオブジェクトタイプの配列を統合して繰り返します.
    lodashのunion With方式は、2つの配列を統合することができ、このデータが重複しているかどうかを判断するために、2つの配列の要素をどう比較するかを制御するためのcomprator方法を提供することができる.
    公式文書のunion With方法の説明はこちらをご覧ください.https://lodash.com/docs/4.17.4#unionWith
    _.unionWith([arrays], [comparator])
    
    理解するのも簡単です.コードを見てください.
    const _ = require('lodash');
    const orgGaming = [
          {
            "enter": new Date("2017-04-25T14:32:12.081Z"),
            "exit": new Date("2017-04-25T14:48:52.082Z"),
          },
          {
            "enter": new Date("2017-04-26T14:32:12.081Z"),
            "exit": new Date("2017-04-26T14:48:52.082Z"),
          }
    ]
    
    const newGaming = [
         {
            "enter": 1493130732081,
            "exit": 1493131732082,
          },
          {
            "enter": 1493130735084,
            "exit": 1493131736087,
          }
    ]
    
    gaming = _.unionWith(orgGaming, newGaming, (value1, value2) => {
        if (typeof value1.enter === 'number' && typeof value2.enter === 'number') {
            return (value1.enter === value2.enter);
        } else if (typeof value1.enter === 'number' && typeof value2.enter === 'object') {
            return (value1.enter === value2.enter.getTime());
        } else if (typeof value1.enter === 'object' && typeof value2.enter === 'number') {
            return (value1.enter.getTime() === value2.enter);
        } else if (typeof value1.enter === 'object' && typeof value2.enter === 'object') {
            return (value1.enter.getTime() === value2.enter.getTime());
        }
    });
    
    console.log(gaming);
    
    ここの肝心なところはuionWithです.いくつかのところに注意が必要です.
  • パラメータの順序、特に最初の2つの配列パラメータ.第一の配列の中のあるメンバーが第二の配列の中のあるメンバーと重複していると判断した場合、第一の配列の中の要素は保留され、第二の配列の中の対応する要素は除去されます.
  • の3番目のパラメータは、2つのパラメータを受け入れることです.つまり、2つのペアが必要な配列のメンバーです.ここでは、2つのメンバーのenterが等しいかどうかを比較して、このメンバーが重複しているかを判断します.
  • は重複するかどうかを判断する時、日記をまずunixtime形式に変換してから比較する必要があります.
  • 最終的には重複した出力を見ることができます.
    [ { enter: 2017-04-25T14:32:12.081Z,
        exit: 2017-04-25T14:48:52.082Z },
      { enter: 2017-04-26T14:32:12.081Z,
        exit: 2017-04-26T14:48:52.082Z },
      { enter: 1493130735084, 
        exit: 1493131736087 } ]
    
    最後に出力されたリストの中には3つのオブジェクトしかありません.その中の一つはもう捨てられました.
    最後に、私たちはmonogoseを通じてこのデータをmongodbに保存すると、前述のようにunixtimeを自動的にDateに変換して保存して、データを統一します.ここでmonogoogleの操作は詳しく説明しません.興味のある友達は自分で実践してもいいです.
    以上は私が対象のタイプからなる二つの配列を合算したいくつかの試みと実践です.もし皆さんがもっと優雅な方法があれば、コメントをください.お先に失礼します
    本文は天地会珠海分舵で編纂して、転載は授権しなければならなくて、称賛をつけることが好きで、突っ込みは評論して下さい、更に交流して公衆番号のtechgogogoに関心を持って下さい、あるいは直接本人の微信zhubaitian 1に連絡して下さい.