mongoose關聯操作

請叫我峰仔仔發表於2017-09-19

mongoose-ref

實現程式碼github
最近在做一個專案涉及到mongoose的關聯查詢等等,之前做的mysql,postgresql比較多,而mongoose用的都是比較簡單的儲存資料,簡單查詢等等。
剛開始涉及ref還是有點小暈的,查詢了相關資源,也可以模模糊糊做出來,但是會有各種報錯。痛下決心研究透徹點,晚上熬夜到2點終於有點小眉目了。

  • node v8.5.0
  • mongodb
  • 結合一個介面理解
  • 結合promise-async-await
  • 一般採用mvc模式,本文就直接在express裡直接寫了

    1. 首先建立了一個mongoose-ref專案

    直接使用了express -e mongoose-ref

    2.在routes/index裡連線mongodb資料庫

    const mongoose = require('mongoose');
    mongoose.connect('mongodb://localhost:27017/ref');複製程式碼

    3.建立4個模型,使用者:User,城市:City,省份:State,國家:Country

    同時建立關聯user->city->state->country
    const Schema = mongoose.Schema;
    const ObjectId = Schema.Types.ObjectId;
    const UserSchema = new Schema({
      username: { type: String },
      userpwd: { type: String },
      userage: { type: Number },
      city: { type: Schema.Types.ObjectId, ref: 'City' },
    });
    const CitySchema = new Schema({
      name: { type: String },
      state: { type: Schema.Types.ObjectId, ref: 'State' }
    });
    const StateSchema = new Schema({
      name: { type: String },
      country: { type: Schema.Types.ObjectId, ref: 'Country' }
    });
    const CountrySchema = new Schema({
      name: { type: String }
    });
    const User = mongoose.model('User', UserSchema);
    const City = mongoose.model('City', CitySchema);
    const State = mongoose.model('State', StateSchema);
    const Country = mongoose.model('Country', CountrySchema);複製程式碼

    4.主要採用promise-async-async進行邏輯處理

    首先建立一個user_getCountryList函式,如下程式碼

    const user_getCountryList = async function (req, res) {
      console.log("/v1/ref start -->" + JSON.stringify(req.body));
      try {
        const respondData = {
          status: res.statusCode,
          data: {},
          error: {}
        };
        const username = req.body.username;
        const userpwd = req.body.userpwd;
        const userage = req.body.userage;
        const usercityname = req.body.usercityname;
        const userstatename = req.body.userstatename;
        const usercountryname = req.body.usercountryname;
        const userInfoCountry = await findUserCountry({ name: usercountryname }, usercountryname);//檢視國家
        const userInfoState = await findUserState({ name: userstatename }, userstatename);//檢視州
        const userInfoCity = await findUserCity({ name: usercityname }, usercityname);//檢視城市
        const userInfo = await findUser({ username: username, }, username,userpwd,userage);//檢視使用者資訊
        const updateInfoUser = await updateUser({ _id: userInfo },userInfoCity);//更新使用者資訊
        const updateInfoCity = await updateCity({ _id: userInfoCity }, userInfoState);//更新城市資訊
        const updateInfoState = await updateState({ _id: userInfoState }, userInfoCountry);//更新州資訊
        return res.json(respondData);
      }
      catch (error) {
        //錯誤處理
        console.log("userCity error -->" + JSON.stringify(error));
        respondData.error = error;
        return res.json(respondData);
      }
    }複製程式碼
    首先檢視傳入的國家在country中有沒有,加入有,返回_id,沒有就建立傳入的國家名,並返回_id,檢視findUserCountry函式對應的邏輯
    const findUserCountry = async function (cnd, country) {
      console.log("findUserCountry start --> " + JSON.stringify(cnd));
      return new Promise(function (resolve, reject) {
        Country.findOne(cnd, function (error, data) {
          console.log("findUserCountry findOne  data --> " + JSON.stringify(data));
          if (error) {
            return reject(error);
          }
          if (data) {
            return resolve(data._id);
          } else {
            const userCountry = new Country({
              name: country
            });
            userCountry.save(function (err, data) {
              if (err) {
                console.log("userCountry.save err-->" + JSON.stringify(err));
                return reject(err);
              }
              console.log("userCountry-->" + JSON.stringify(data));
              return resolve(data._id);
            });
          }
        });
      })
    }複製程式碼
    同理傳入的州,城市,使用者資訊以同樣的方式返回_id

    接下來就要進行關聯user->city->state->country

    通俗的說就是在User表中city儲存City表中所需要的_id;也就是之前返回的_id這時就可以用到,可以參考updateUser函式
     const updateUser = async function (cnd, cityid) {
      console.log("updateUser start --> " + JSON.stringify(cnd));
      return new Promise(function (resolve, reject) {
        User.update(cnd, { $set: { city: cityid } }, function (error, data) {
          console.log("updateUser findOne  data --> " + JSON.stringify(data));
          if (error) {
            return reject(error);
          }
          return resolve(data);
        });
      })
    }複製程式碼
    可以使用postman模擬資料,如圖:

postman模擬資料
postman模擬資料

這時就把City對應的_id寫進了User表中,可以檢視錶,如圖:

User表中資料
User表中資料

City表中資料
City表中資料

同理user->city->state->country資料都可以寫進不同的表中。

5.使用populate關聯查詢

當傳入username 時,使用populate關聯查詢,可以查詢出這個人的所以資訊

 User.find({ username: user_name })
    .populate('city')
    .exec(function (err, docs) {
      City.find({ _id: docs[0].city._id })
        .populate('state')
        .exec(function (err, doc) {
          State.find({ _id: doc[0].state._id })
            .populate('country')
            .exec(function (err, result) {
              const userInfo = {};
              userInfo.username = docs[0].username;
              userInfo.userpwd = docs[0].userpwd;
              userInfo.userage = docs[0].userage;
              userInfo.usercity = doc[0].name;
              userInfo.userstate = result[0].name;
              userInfo.usercountry = result[0].country.name;
              respondData.data.push(userInfo);
              return res.json(respondData);
            })
        })
    });複製程式碼

使用postman模擬介面如下

Postman模擬介面關聯查詢
Postman模擬介面關聯查詢

當然這個關聯查詢也可以使用promise-async-await不過有時候看著這回撥,層層包含還挺好看,或者這也是js的一大美感呢

相關文章