node.js - 我应该使用什么数据类型来使用 MongoDB 存储图像?

我有一张带有 base64 的图片,例如

data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCcUGhvdG9zaG9w....

如何保存在数据库中?架构中字段的类型应该是什么?缓冲?

最佳答案

简短的答案是存储为 "Binary" ,在 Mongoose 模式中,您可以使用 Buffer 来执行此操作。

更长的形式是演示从原始二进制文件开始并再次返回的往返转换。在大多数实际情况中,Base64 编码/解码不是必要的步骤,仅用于演示:

  • 从文件中读取图像(或任何二进制数据)
  • Base64 编码该数据(只是为了表明它可以完成) - 可选
  • 从 Base64 转回二进制数据(只是为了表明可以做到)- 可选
  • 在数据库中存储二进制数据
  • 从数据库中读取二进制数据
  • 将二进制数据输出到新文件

所以Schema部分很简单,使用Buffer:

var albumSchema = new Schema({
  name: String,
  image: Buffer
})

那么我们要做的就是按照流程,将二进制数据放入属性中,然后再次读取出来。

请注意,如果您直接来自带有 MIME 类型的字符串,例如:

  data:image/png;base64,long-String

只需使用 JavaScript .split() 并为 base64 字符串本身获取第二个数组索引:

var string = "data:image/png;base64,long-String"
var bindata = new Buffer(string.split(",")[1],"base64");

这是一个包含完整演示的 list :

const async = require('async'),
      mongoose = require('mongoose'),
      Schema = mongoose.Schema,
      fs = require('fs');

mongoose.Promise = global.Promise;
mongoose.set('debug',true);
mongoose.connect('mongodb://localhost/test');

var albumSchema = new Schema({
  name: String,
  image: Buffer
})

const Album = mongoose.model('Albumn', albumSchema);


async.series(
  [
    (callback) =>
      async.each(mongoose.models,(model,callback) =>
        model.remove({},callback),callback),

    (callback) =>
      async.waterfall(
        [
          (callback) => fs.readFile('./burger.png', callback),

          (data,callback) => {
            // Convert to Base64 and print out a bit to show it's a string
            let base64 = data.toString('base64');
            console.log(base64.substr(0,200));

            // Feed out string to a buffer and then put it in the database
            let burger = new Buffer(base64, 'base64');
            Album.create({
              "title": "burger",
              "image": burger
            },callback)
          },

          // Get from the database
          (album,callback) => Album.findOne().exec(callback),

          // Show the data record and write out to a new file.
          (album, callback) => {
            console.log(album);
            fs.writeFile('./output.png', album.image, callback)
          }

        ],
        callback
      )


  ],
  (err) => {
    if (err) throw err;
    mongoose.disconnect();
  }
)

NOTE The example was originally given with asyncJS and older mongoose API, which notably has different connection options as shown in more modern and current API examples. Refer to these instead for testing on current NodeJS LTS releases:

或者使用更现代的语法和 API 用法进行比较:

const fs = require('mz/fs');
const { Schema } = mongoose = require('mongoose');

const uri = 'mongodb://localhost:27017/test';
const opts = { useNewUrlParser: true };

mongoose.Promise = global.Promise;
mongoose.set('debug', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);

const albumSchema = new Schema({
  name: String,
  image: Buffer
});

const Album = mongoose.model('Album', albumSchema);

(async function() {

  try {

    const conn = await mongoose.connect(uri, opts);

    await Promise.all(
      Object.entries(conn.models).map(([k, m]) => m.deleteMany())
    )

    let data = await fs.readFile('./burger.png');

    // Convert to Base64 and print out a bit to show it's a string
    let base64 = data.toString('base64');
    console.log(base64.substr(0,200));

    // Feed out string to a buffer and then put it in the database
    let burger = new Buffer(base64, 'base64');
    await Album.create({ "title": "burger", "image": burger });

    // Get from the database
    // - for demo, we could have just used the return from the create() instead
    let album =  Album.findOne();

    // Show the data record and write out to a new file.
    console.log(album);
    await fs.writeFile('./output.png', album.image)


  } catch(e) {
    console.error(e);
  } finally {
    mongoose.disconnect()
  }

})()

即使使用“plain promises”,这也是首选,或者您仍在使用没有 async/await 支持的 NodeJS。但是你really should not be, considering v6.x reaches end of life in April 2019 :

// comments stripped - refer above
const fs = require('mz/fs');
const { Schema } = mongoose = require('mongoose');

const uri = 'mongodb://localhost:27017/test';
const opts = { useNewUrlParser: true };

mongoose.Promise = global.Promise;
mongoose.set('debug', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);

const albumSchema = new Schema({
  name: String,
  image: Buffer
});

mongoose.connect(uri, opts)
  .then(conn =>
    Promise.all(
      Object.entries(conn.models).map(([k, m]) => m.deleteMany())
    )
  )
  .then(() => fs.readFile('./burger.png'))
  .then(data => {
    let base64 = data.toString('base64');
    console.log(base64.substr(0,200));
    let burger = new Buffer(base64, 'base64');
    return Album.create({ "title": "burger", "image": burger });
  })
  .then(() => Album.findOne() )
  .then(album => {
    console.log(album);
    return fs.writeFile('./output.png', album.image)
  })
  .catch(console.error)
  .then(() => mongoose.disconnect());

还有一个 burger.png 可以玩:

Also kudos to How to reduce image size on Stack Overflow which allows the sample image here to not appear as "huge" as it originally was, and yet still download at full size.

https://stackoverflow.com/questions/44869479/

相关文章:

node.js - Node/Express - 保护客户端/服务器之间通信的好方法

mongodb - 使用键值对将 mongo 数组转换为对象

node.js - 查找未邀请任何用户的用户

c# - ReadBsonType 只能在 State 为 Type 时调用,不能在 State 为

mongodb - Meteor 1.4.1.1 上副本集的正确 MONGO_URL 设置是什么

node.js - Mongoose 类型错误 : User is not a constructo

json - 使用 Python 从 MongoDB 文档创建 JSON 文件

javascript - 为已登录的用户手动创建 Passport session

java - 如何防止连接池在 mongodb 上使用 java 驱动程序关闭?

node.js - 我可以在 MongoDB 的聚合查询中申请 forEach 吗?