我应该使用什么数据类型来存储MongoDB的图像?

时间:2017-07-02 09:47:28

标签: node.js mongodb mongoose

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

<div class="sec-1">
    <h2>Introducing 'Keeva' world's smartest assistant.</h2>
    <div class="flex-box">
        <div>
            <p class="sales-copy">Keeva smartphone app helps you organize your work schedule, meetings, project deadlines and much more.</p>
                        <!-- Download Buttons -->
                    <img class="download-btns" src="img/playstore-1.png">
                    <img class="download-btns" src="img/iphone-1.png">
        </div>
        <!-- Phone 0 image -->
        <img class="phone-img" src="img/iphone-cut.png" alt="phone image">          
    </div>
</div>

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

1 个答案:

答案 0 :(得分:6)

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

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

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

因此,架构部分很简单,只需使用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");

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

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();
  }
)
  

注意该示例最初是使用asyncJS和较旧的mongoose API提供的,它们具有不同的连接选项,如更现代和最新的API示例所示。请参考这些来测试当前的NodeJS LTS版本:

或者使用更现代的语法和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()
  }

})()

即使是“普通承诺”,或者您仍然使用没有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

enter image description here

  

同样赞赏How to reduce image size on Stack Overflow,它允许此处的示例图像不像原来那样显示为“巨大”,但仍以全尺寸下载。