Как подключить несколько mongodbs и заполнить данные в разных базах данных - PullRequest
0 голосов
/ 28 марта 2020

Я разрабатывал API, который использует несколько MongoDB для хранения определенных c данных, которые будут использоваться в разных приложениях.

Основная проблема, с которой я столкнулся, заключается в правильном соединении двух или более MongoDB и затем заполните поля mongoose.Schema.Types.ObjectId соответствующими данными, хранящимися в отдельной MongoDB.

Это подход, который я нашел в inte rnet, но он не сработал, как ожидалось.

Модели в базе данных 1:

Модели / Post. js

const mongoose = require('mongoose');

var db = mongoose.createConnection(process.env.ATLAS_URI_BLOG, {
  useNewUrlParser: true,
  useCreateIndex: true,
  useUnifiedTopology: true,
});

const PostSchema = new mongoose.Schema({
  id: {
    type: String,
    required: true,
  },
  title: {
    type: String,
    required: true,
  },
  type: {
    type: String,
    required: true,
  },
  category: {
    type: String,
    required: true,
  },
  slug: {
    type: String,
    required: true,
  },
  content: {
    type: String,
    required: true,
  },
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true,
  },
  tags: {
    type: [],
    required: false,
  },
  comments: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'Comment',
      required: false,
    }
  ],
  cover: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'PostCover',
    required: true,
  },
  howManyRead: {
    type: Number,
    required: true,
    default: 0,
  },
  publishedOn: {
    type: Date,
    default: Date.now,
  },
  updatedOn: {
    type: Date,
    default: null,
  },
});

const Post = db.model('Post', PostSchema);

module.exports = Post;

Модели / PostCover. js

const mongoose = require('mongoose');
const aws = require('aws-sdk');
const fs = require('fs');
const path = require('path');
const {
  promisify,
} = require('util');

var db = mongoose.createConnection(process.env.ATLAS_URI_BLOG, {
  useNewUrlParser: true,
  useCreateIndex: true,
  useUnifiedTopology: true,
});

const s3 = new aws.S3();

const PostCoverSchema = new mongoose.Schema({
  id: String,
  name: String,
  size: Number,
  key: String,
  url: String,
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

PostCoverSchema.pre('save', function () {
  if (!this.url) {
    this.url = `https://${process.env.BUCKET_NAME}.s3.amazonaws.com/${this.key}`;
  }
});

PostCoverSchema.pre('remove', function () {
  if (process.env.STORAGE_TYPE === 's3') {
    return s3
      .deleteObject({
        Bucket: process.env.BUCKET_NAME,
        Key: this.key,
      })
      .promise()
      .then((response) => {
        console.log(response.status);
      })
      .catch((response) => {
        console.log(response.status);
      });
  }
  return promisify(fs.unlink)(
    path.resolve(__dirname, '..', '..', 'tmp', 'uploads', this.key),
  );
});

const PostCover =  db.model('PostCover', PostCoverSchema);

module.exports = PostCover;

Модели в базе данных 2 :

models / User. js

const mongoose = require('mongoose');

var db2 = mongoose.createConnection(process.env.ATLAS_URI_USER, {
  useNewUrlParser: true,
  useCreateIndex: true,
  useUnifiedTopology: true,
});

const UserSchema = new mongoose.Schema({
  id: {
    type: String,
    require: true,
  },
  name: {
    type: String,
    required: false,
  },
  email: {
    type: String,
    required: false,
  },
  username: {
    type: String,
    required: false,
  },
  password: {
    type: String,
    required: false,
  },
  profileImage: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'UserProfileImage',
    required: false,
  },
  isAdmin: {
    type: Boolean,
    require: true,
  },
  origin: {
    type: String,
    required: true,
  },
  posts: [
    {
      type: mongoose.Schema.Types.ObjectId,
      required: false,
    }
  ],
  quote: {
    type: String,
    required: false,
  },
  following: {
    type: [],
    required: false,
  },
  followers: {
    type: [],
    required: false,
  },
  socialMedia: {
    github: {
      type: String,
      required: false,
    },
    linkedin: {
      type: String,
      required: false,
    },
    twitter: {
      type: String,
      required: false,
    },
  },
  createdOn: {
    type: Date,
    default: Date.now,
  },
});

const User = db2.model('User', UserSchema);

module.exports = User;

models / UserProfileImage. js

/* eslint-disable no-console */
/* eslint-disable func-names */
const mongoose = require('mongoose');
const aws = require('aws-sdk');
const fs = require('fs');
const path = require('path');
const {
  promisify,
} = require('util');

var db2 = mongoose.createConnection(process.env.ATLAS_URI_USER, {
  useNewUrlParser: true,
  useCreateIndex: true,
  useUnifiedTopology: true,
});


const s3 = new aws.S3();

const UserProfileImageSchema = new mongoose.Schema({
  id: String,
  name: String,
  size: Number,
  key: String,
  url: String,
  origin: String,
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

UserProfileImageSchema.pre('save', function () {
  if (this.origin !== 'Github') {
    if (!this.url) {
      this.url = `${process.env.APP_URL}/files/${this.key}`;
    }
  }
});

UserProfileImageSchema.pre('remove', function () {
  if (process.env.STORAGE_TYPE === 's3') {
    return s3
      .deleteObject({
        Bucket: process.env.BUCKET_NAME,
        Key: this.key,
      })
      .promise()
      .then((response) => {
        console.log(response.status);
      })
      .catch((response) => {
        console.log(response.status);
      });
  }
  return promisify(fs.unlink)(
    path.resolve(__dirname, '..', '..', 'tmp', 'uploads', this.key),
  );
});

module.exports = db2.model('UserProfileImage', UserProfileImageSchema);

Следующий файл - это маршрут, который должен запрашивать базы данных. и заполните соответствующие поля соответствующими данными.

routs / blog. js

const express = require('express');

const app = express();

app.use(cors());

const Post = require('../models/blog/Post');
const PostCover = require('../models/blog/PostCover');
const User = require('../models/user/User');

// My first failing approach. It doesn't populate the fields `cover`, `author` and `profileImage`, it returns `null` instead.
app.get('/home/articles', async (req, res) => {
  const postsList = [];
  Post.find({
    type: 'Article',
  })
    .sort({ publishedOn: -1 })
    .limit(6)
    .populate('cover')
    .populate({
      path: 'author',
      populate: {
        path: 'profileImage',
        model: 'UserProfileImage',
      },
    })
    .then((posts) => {
        posts.map((post) => {
          postsList.push({
            id: post.id,
            title: post.title,
            slug: post.slug,
            category: post.category,
            cover: post.cover,
            author: post.author,
            publishedOn: post.publishedOn,
            updateOn: post.updateOn,
          });
        });

        res.status(200).send(postsList);
    })
    .catch((err) => {
      res.json({
        err,
      });
    });
});

const getAuthor = async (authorId) => {
  const user = await User.findOne({
    _id: authorId
  })
  const userImage = await UserProfileImage.findOne({
    _id: user.profileImage
  });

  return {
    socialMedia: user.socialMedia,
    posts: user.posts,
    following: user.following,
    followers: user.followers,
    _id: user._id,
    id: user.id,
    name: user.name,
    email: user.email,
    quote: user.quote,
    username: user.username,
    password: user.password,
    profileImage: userImage,
    isAdmin: user.isAdmin,
    origin: user.origin,
    createdOn: user.createdOn,
    __v: user.__v,
  }
}

const getCover = async (coverId) => {
  try {
    const cover = await PostCover.findOne({
      _id: coverId,
    });
    return cover
  } catch(err) {
    console.log(err);
    return {}
  }
}

// My second work around but it doesn't work well.
app.get('/home/articles', async (req, res) => {
  let postsList = [];
  try {
    const posts = await Post.find({
      type: 'Article',
    })
    .sort({ publishedOn: -1 })
    .limit(6)

    let postsLen = posts.length;
    posts.map(async (post, i) => {
      postsList.push({
        tags: post.tags,
        comments: post.comments,
        howManyRead: post.howManyRead,
        updatedOn: post.updatedOn,
        _id: post._id,
        id: post.id,
        type: post.type,
        category: post.category,
        title: post.title,
        slug: post.slug,
        cover: await getCover(post.cover),
        content: post.content,
        author: await getAuthor(post.author),
        publishedOn: post.publishedOn,
        __v: post.__v
      })
      if (postsLen === i + 1) {
        res.json(postsList)
      }
    });
  } catch(err) {
    console.log(err)
  }
});

Таким образом, с этим подходом в итоге получается, что я могу подключиться и запросить из разных баз данных индивидуально. Но я не могу заполнить поля mongoose.Schema.Types.ObjectId, основанные на данных из отдельной базы данных, с помощью команды .populate(), даже те из той же базы данных, что и поле cover в models/Post.js.

Как мне поступить с этой проблемой?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...