Nodejs mongoose 的关联操作

Nodejs mongoose 的关联操作

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 模拟接口请求 这时就把 City 对应的_id 写进了 User 表中,可以查看表,如图: User 表中数据 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 模拟接口关联查询

当然这个关联查询也可以使用 promise-async-await 不过有时候看着这回调,层层包含还挺好看,或者这也是 js 的一大美感呢


4 回复

为什么 Markdown 在这里看起来那么怪呢


我记得 mongoose 如果 exec 不传 cb 就返回 promise 的吧 既然都用上了 async/await 了 就彻底一点吧

可以彻底的,最后一句话说了,层层包含还挺好看,或者这也是 js 的一大美感呢,哈哈

在Node.js中,Mongoose是一个用于与MongoDB进行交互的对象数据建模库。Mongoose支持多种类型的关联操作,主要包括一对一、一对多和多对多关系。下面以一对多关系(例如,一个用户可以有多个帖子)为例,展示如何使用Mongoose进行关联操作。

首先,定义两个Schema:User和Post。

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  name: String,
  posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }]
});

const postSchema = new mongoose.Schema({
  title: String,
  content: String,
  user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
});

const User = mongoose.model('User', userSchema);
const Post = mongoose.model('Post', postSchema);

接下来,进行关联操作。例如,创建一个用户,然后为该用户创建多个帖子。

async function createUserAndPosts() {
  const user = await User.create({ name: 'John Doe' });
  await Post.create([{ title: 'Post 1', content: 'Content 1', user: user._id },
                     { title: 'Post 2', content: 'Content 2', user: user._id }]);

  const posts = await User.findById(user._id).populate('posts').exec();
  console.log(posts.posts);
}

createUserAndPosts().catch(console.error);

在上述代码中,populate方法用于自动将posts数组中的ObjectId替换为对应的Post文档。这样,你就成功地实现了Node.js中Mongoose的关联操作。

回到顶部