成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

使用React、Node.js、MongoDB、Socket.IO開(kāi)發(fā)一個(gè)角色投票應(yīng)用的學(xué)習(xí)過(guò)程(三

JessYanCoding / 2993人閱讀

摘要:將就用一下,能實(shí)現(xiàn)相同的功能就可以了。的方法可以從返回最大值,但是新版中的不行,只能通過(guò)這樣的方式返回最大值。

前篇

使用React、Node.js、MongoDB、Socket.IO開(kāi)發(fā)一個(gè)角色投票應(yīng)用的學(xué)習(xí)過(guò)程(一)
使用React、Node.js、MongoDB、Socket.IO開(kāi)發(fā)一個(gè)角色投票應(yīng)用的學(xué)習(xí)過(guò)程(二)

原文第十三步,Express API路由

第一個(gè)路由是用來(lái)創(chuàng)建角色的

app.post("/api/characters",(req,res,next) => {
  let gender = req.body.gender;
  let characterName = req.body.name;
  let characterIdLookupUrl = "https://api.eveonline.com/eve/CharacterId.xml.aspx?names=" + characterName;

  const parser = new xml2js.Parser();

  async.waterfall([
    function(callback) {
      request.get(characterIdLookupUrl,(err,request,xml) => {
        if(err) return next(err);
        parser.parseString(xml,(err,parsedXml) => {
          try {
            let characterId = parsedXml.eveapi.result[0].rowset[0].row[0].$.characterID;

            app.models.character.findOne({ characterId: characterId},(err,model) => {
              if(err) return next(err);

              if(model) {
                return res.status(400).send({ message: model.name + " is alread in the database"});
              }

              callback(err,characterId);
            });
          } catch(e) {
            return res.status(400).send({ message: " xml Parse Error"});
          }
        });
      });
    },
    function(characterId) {
      let characterInfoUrl = "https://api.eveonline.com/eve/CharacterInfo.xml.aspx?characterID=" + characterId;
      console.log(characterInfoUrl);
      request.get({ url: characterInfoUrl },(err,request,xml) => {
        if(err) return next(err);
        parser.parseString(xml, (err,parsedXml) => {
          if (err) return res.send(err);
          try{
            let name = parsedXml.eveapi.result[0].characterName[0];
            let race = parsedXml.eveapi.result[0].race[0];
            let bloodline = parsedXml.eveapi.result[0].bloodline[0];
            app.models.character.create({
              characterId: characterId,
              name: name,
              race: race,
              bloodline: bloodline,
              gender: gender
            },(err,model) => {
              if(err) return next(err);
              res.send({ message: characterName + " has been added successfully!"});
            });
          } catch (e) {
            res.status(404).send({ message: characterName + " is not a registered citizen of New Eden",error: e.message });
          }
        });
      });
    }
  ]);
});

是不是看起來(lái)和原文的基本一模一樣,只不過(guò)把var 變成了let 匿名函數(shù)變成了ES6的"=>"箭頭函數(shù),雖然我用的是warterline而原文中用的是mongoose但是包括方法名基本都一樣,所以我感覺(jué)waterline是在API上最接近mongoose

順便說(shuō)一下,我為什么不喜歡mongodb,僅僅是因?yàn)橛幸淮挝野惭b了,只往里面寫了幾條測(cè)試數(shù)據(jù),按文本算最多幾kb,但第二天重啟機(jī)器的時(shí)候,系統(tǒng)提示我,我的/home分區(qū)空間不足了(雙系統(tǒng)分區(qū)分給linux分小了本來(lái)就不大),結(jié)果一查mongodb 的data文件 有2G多,我不知道什么原因,可能是配置不對(duì)還是別的什么原因,反正,當(dāng)天我就把它刪除了,

完成了這個(gè)API我們就可以往數(shù)據(jù)庫(kù)里添加?xùn)|西了,不知道哪些用戶名可以用?相當(dāng)簡(jiǎn)單,反正我用的全是一名人的名字(英文名),外國(guó)人也喜歡搶注名字,嘿嘿嘿

原文第十三步,Home組件

基本保持和原文一樣,只是用lodash 替換了 underscore

一開(kāi)始我看到網(wǎng)上介紹lodash是可以無(wú)縫替換underscore,中要修改引用就可以,但是我用的版本是4.11.2已經(jīng)有很多方法不一樣了,還去掉了不少方法(沒(méi)有去關(guān)注underscore是不是也在最新版本中有同樣的改動(dòng))

原文中:

......
import {first, without, findWhere} from "underscore";
......

var loser = first(without(this.state.characters, findWhere(this.state.characters, { characterId: winner }))).characterId;

......

修改為:

......
import {first, filter} from "lodash";
......

let loser = first(filter(this.state.characters,item => item.characterId != winner )).characterId;

findWhere 在最新版本的lodash中已經(jīng)不存正,我用了filter來(lái)實(shí)現(xiàn)相同功能。

第十四步:Express API 路由(2/2) GET /api/characters

原文的實(shí)現(xiàn)方法

/**
 * GET /api/characters
 * Returns 2 random characters of the same gender that have not been voted yet.
 */
app.get("/api/characters", function(req, res, next) {
  var choices = ["Female", "Male"];
  var randomGender = _.sample(choices);

  Character.find({ random: { $near: [Math.random(), 0] } })
    .where("voted", false)
    .where("gender", randomGender)
    .limit(2)
    .exec(function(err, characters) {
      if (err) return next(err);

      if (characters.length === 2) {
        return res.send(characters);
      }

      var oppositeGender = _.first(_.without(choices, randomGender));

      Character
        .find({ random: { $near: [Math.random(), 0] } })
        .where("voted", false)
        .where("gender", oppositeGender)
        .limit(2)
        .exec(function(err, characters) {
          if (err) return next(err);

          if (characters.length === 2) {
            return res.send(characters);
          }

          Character.update({}, { $set: { voted: false } }, { multi: true }, function(err) {
            if (err) return next(err);
            res.send([]);
          });
        });
    });
});

可以看到原文中用{ random: { $near: [Math.random(), 0] } }做為查詢條件從而在數(shù)據(jù)庫(kù)里取出兩條隨機(jī)的記錄返回給頁(yè)面進(jìn)行PK,前文說(shuō)過(guò)random的類型在mysql沒(méi)有類似的,所以我把這個(gè)字段刪除了。本來(lái)mysql,可以用order by rand() 之類的方法但是,waterlinesort(order by rand())不被支持,所以我是把所有符合條件的記錄取出來(lái),能過(guò)lodashsampleSize方法從所有記錄中獲取兩天隨機(jī)記錄。

app.get("/api/characters", (req,res,next) => {
  let choice = ["Female", "Male"];
  let randomGender = _.sample(choice);
  //原文中是通過(guò)nearby字段來(lái)實(shí)現(xiàn)隨機(jī)取值,waterline沒(méi)有實(shí)現(xiàn)mysql order by rand()返回隨機(jī)記錄,所以返回所有結(jié)果,用lodash來(lái)處理
  app.models.character.find()
    .where({"voted": false})
    .exec((err,characters) => {
      if(err) return next(err);
      
      //用lodash來(lái)取兩個(gè)隨機(jī)值
      let randomCharacters = _.sampleSize(_.filter(characters,{"gender": randomGender}),2); 
      if(randomCharacters.length === 2){
      //console.log(randomCharacters);
        return res.send(randomCharacters);
      }

      //換個(gè)性別再試試
      let oppsiteGender = _.first(_.without(choice, randomGender));
      let oppsiteCharacters = _.sampleSize(_.filter(characters,{"gender": oppsiteGender}),2); 

      if(oppsiteCharacters === 2) {
        return res.send(oppsiteCharacters);
      }
      //沒(méi)有符合條件的character,就更新voted字段,開(kāi)始新一輪PK
      app.models.character.update({},{"voted": false}).exec((err,characters) => {
        if(err) return next(err);
        return res.send([]);
      });
      


    });

});

在數(shù)據(jù)量大的情況下,這個(gè)的方法性能上肯定會(huì)有問(wèn)題,好在我們只是學(xué)習(xí)過(guò)程,數(shù)據(jù)量也不大。將就用一下,能實(shí)現(xiàn)相同的功能就可以了。

GET /api/characters/search

這個(gè)API之前還有兩個(gè)API,和原文基本一樣,所做的修改只是用了ES6的語(yǔ)法,就不浪費(fèi)篇幅了,可以去我的github看

這一個(gè)也只是一點(diǎn)mongoosewaterline的一點(diǎn)點(diǎn)小區(qū)別
原文中mongoose的模糊查找是用正則來(lái)做的,mysql好像也可以,但是warterline中沒(méi)有找到相關(guān)方法(它的文檔太簡(jiǎn)陋了)
所以原文中

app.get("/api/characters/search", function(req, res, next) {
  var characterName = new RegExp(req.query.name, "i");

  Character.findOne({ name: characterName }, function(err, character) {
    ......

我改成了

app.get("/api/characters/search", (req,res,next) => {
  app.models.character.findOne({name:{"contains":req.query.name}}, (err,character) => {
    .....

通過(guò)contains來(lái)查找,其實(shí)就是like %sometext%的方法來(lái)實(shí)現(xiàn)
下面還有兩個(gè)方法修改的地方也大同小異,就不仔細(xì)講了,看代碼吧

GET /api/stats

這個(gè)是原文最后一個(gè)路由了,
原文中用了一串的函數(shù)來(lái)獲取各種統(tǒng)計(jì)信息,原作者也講了可以優(yōu)化,哪我們就把它優(yōu)化一下吧

app.get("/api/stats", (req,res,next) => {
  let asyncTask = [];
  let countColumn = [
        {},
        {race: "Amarr"},
        {race: "Caldari"},
        {race: "Gallente"},
        {race: "Minmatar"},
        {gender: "Male"},
        {gender: "Female"}
      ];
  countColumn.forEach(column => {
    asyncTask.push( callback => {
      app.models.character.count(column,(err,count) => {
        callback(err,count);
      });
    })
  });

  asyncTask.push(callback =>{
    app.models.character.find()
              .sum("wins")
              .then(results => {
                callback(null,results[0].wins);
              });
  } );

  asyncTask.push(callback => {
    app.models.character.find()
              .sort("wins desc")
              .limit(100)
              .select("race")
              .exec((err,characters) => {
                if(err) return next(err);

                let raceCount = _.countBy(characters,character => character.race);
                console.log(raceCount);
                let max = _.max(_.values(raceCount));
                console.log(max);
                let inverted = _.invert(raceCount);
                let topRace = inverted[max];
                let topCount = raceCount[topRace];

                

                callback(err,{race: topRace, count: topCount});
              });
  });

  asyncTask.push(callback => {
    app.models.character.find()
              .sort("wins desc")
              .limit(100)
              .select("bloodline")
              .exec((err,characters) => {
                if(err) return next(err);

                let bloodlineCount = _.countBy(characters,character => character.bloodline);
                let max = _.max(_.values(bloodlineCount));
                let inverted = _.invert(bloodlineCount);
                let topBloodline = inverted[max];
                let topCount = bloodlineCount[topBloodline];

                callback(err,{bloodline: topBloodline, count: topCount});
              });
  });

  async.parallel(asyncTask,(err,results) => {
    if(err) return next(err);
    res.send({
      totalCount: results[0],
          amarrCount: results[1],
          caldariCount: results[2],
          gallenteCount: results[3],
          minmatarCount: results[4],
          maleCount: results[5],
          femaleCount: results[6],
          totalVotes: results[7],
          leadingRace: results[8],
          leadingBloodline:results[9]
    });
  }) 
});

我把要統(tǒng)計(jì)數(shù)據(jù)的字段放入一個(gè)數(shù)組countColumn通過(guò)forEach把push到asyncTask,最后兩個(gè)統(tǒng)計(jì)方法不一樣的函數(shù),多帶帶push,最后用async.parallel方法執(zhí)行并獲得結(jié)果。

underscore的max方法可以從{a:1,b:6,d:2,e:3}返回最大值,但是lodash新版中的不行,只能通過(guò)_.max(_.values(bloodlineCount))這樣的方式返回最大值。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/79433.html

相關(guān)文章

  • 使用ReactNode.js、MongoDBSocket.IO開(kāi)發(fā)一個(gè)角色投票應(yīng)用學(xué)習(xí)過(guò)程(二

    摘要:吐完槽,還是開(kāi)始第十二部分的改動(dòng)吧,這是開(kāi)始涉及到數(shù)據(jù)庫(kù)了,原文用我用改動(dòng)就比較大了。后篇使用開(kāi)發(fā)一個(gè)角色投票應(yīng)用的學(xué)習(xí)過(guò)程三 前篇 使用React、Node.js、MongoDB、Socket.IO開(kāi)發(fā)一個(gè)角色投票應(yīng)用的學(xué)習(xí)過(guò)程(一) 這篇主要講一下waterline的初始化,原文用的是mongoose 原文第十二步 一下子就到十二步了,因?yàn)樵募衦eact部分的代碼本來(lái)就是用E...

    jsdt 評(píng)論0 收藏0
  • 使用React、Node.jsMongoDB、Socket.IO開(kāi)發(fā)一個(gè)角色投票應(yīng)用學(xué)習(xí)過(guò)程(一

    摘要:本項(xiàng)目是對(duì)使用開(kāi)發(fā)一個(gè)角色投票應(yīng)用的學(xué)習(xí)過(guò)程。到這里為止沒(méi)有遇到多大的坑,最多的往往是拼寫錯(cuò)誤引起的問(wèn)題,唯一由于拼寫導(dǎo)致,但不提示錯(cuò)誤的是我打成了運(yùn)行的時(shí)候服務(wù)器一直沒(méi)有響應(yīng),找了好久才找到這個(gè)錯(cuò)誤后篇使用開(kāi)發(fā)一個(gè)角色投票應(yīng)用的學(xué)習(xí)過(guò)程二 本項(xiàng)目是對(duì)使用React、Node.js、MongoDB、Socket.IO開(kāi)發(fā)一個(gè)角色投票應(yīng)用的學(xué)習(xí)過(guò)程。 英文原文:Create a char...

    loonggg 評(píng)論0 收藏0
  • node技術(shù)棧 - 收藏集 - 掘金

    摘要:異步最佳實(shí)踐避免回調(diào)地獄前端掘金本文涵蓋了處理異步操作的一些工具和技術(shù)和異步函數(shù)。 Nodejs 連接各種數(shù)據(jù)庫(kù)集合例子 - 后端 - 掘金Cassandra Module: cassandra-driver Installation ... 編寫 Node.js Rest API 的 10 個(gè)最佳實(shí)踐 - 前端 - 掘金全文共 6953 字,讀完需 8 分鐘,速讀需 2 分鐘。翻譯自...

    王偉廷 評(píng)論0 收藏0
  • 【全?!?em>使用Node、Express、Angular、MongoDB構(gòu)建一個(gè)實(shí)時(shí)問(wèn)卷調(diào)查應(yīng)用程序

    摘要:鑒于此目的,我決定快速構(gòu)建一個(gè)用于此目的的問(wèn)卷調(diào)查應(yīng)用程序。這將啟動(dòng)一個(gè)服務(wù)器并將應(yīng)用程序部署到該服務(wù)器。圖應(yīng)用程序配置基礎(chǔ)前端這個(gè)問(wèn)卷調(diào)查應(yīng)用程序?qū)ΤR?jiàn)用戶界面和布局使用了框架。 全棧教程。轉(zhuǎn)自 使用 Node.js、Express、AngularJS 和 MongoDB 構(gòu)建一個(gè)實(shí)時(shí)問(wèn)卷調(diào)查應(yīng)用程序 最近,在向大學(xué)生們介紹 HTML5 的時(shí)候,我想要對(duì)他們進(jìn)行問(wèn)卷調(diào)查,并向他們顯...

    BigTomato 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<