问题
For my project I'm trying to create an audio player. The database aspect of storing files is new to me as I've only stored strings before.
So far, what I've been able to do is:
Store the audio file into the database.(I'm linking to a file here for simplicity but in the future it will be uploaded)
Retrieve the audio file as an object.
Store the audio file in the public folder for use.
Server side code(the route code is separate from the server code)
let fs = require('fs');
var bodyParser = require('body-parser')
var urlencodedParser = bodyParser.urlencoded({
extended: false
})
const MongoClient = require('mongodb').MongoClient;
const Binary = require('mongodb').Binary;
const ObjectId = require('mongodb').ObjectId;
module.exports = function(app) {
app.get('/music', function(req, res) {
//STEP ONE
var data = fs.readFileSync(__dirname + '/../public/recordings/Piso 21 - Puntos Suspensivos.mp3');
var insert_data = {};
insert_data.name = 'Piso 21 - Puntos Suspensivos.mp3';
insert_data.file_data = Binary(data);
MongoClient.connect("mongodb://localhost/songs", {
useNewUrlParser: true
}, function(err, db) {
if (err) throw err;
var dbo = db.db("songs");
dbo.collection("song").insertOne(insert_data, function(err, res) {
if (err) throw err;
console.log("1 document inserted");
db.close();
});
});
//STEP TWO
MongoClient.connect("mongodb://localhost/songs", {
useNewUrlParser: true
}, function(err, db) {
if (err) throw err;
var dbo = db.db("songs");
dbo.collection("song").findOne({
name: 'Piso 21 - Puntos Suspensivos.mp3'
}, function(err, result) {
if (err) throw err;
db.close();
//STEP THREE
fs.writeFile(result.name, result.file_data.buffer, function(err) {
if (err) throw err;
console.log(result);
});
});
});
res.render('audio');
});
The third step is what I don't what to do. I'd like to send the result
object to the audio.ejs
page and somehow give the audio tag
access to it without having to save it in the public folder an then have to delete it after use.
Something like this,
STEP THREE
res.render('audio', result);
and somehow give an audio tag
access to it in the audio.ejs
page
UPDATE
let fs = require('fs');
var bodyParser = require('body-parser')
var urlencodedParser = bodyParser.urlencoded({ extended: false })
const MongoClient = require('mongodb');
const Binary = require('mongodb').Binary;
const ObjectId = require('mongodb').ObjectId;
const Grid = require('gridfs-stream');
const db = new MongoClient.Db('songs', new MongoClient.Server("localhost", 27017));
const gfs = Grid(db, MongoClient);
const bcrypt = require('bcryptjs');
module.exports = function(app){
app.get('/audio/:filename', function (req, res) {
MongoClient.connect("mongodb://localhost/songs", { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
var dbo = db.db("songs");
dbo.collection("song").findOne({name: req.params.filename}, function(err, result){
if (err) throw err;
db.close();
const readstream = gfs.createReadStream(result.file_data);
readstream.on('error', function (error) {
res.sendStatus(500);
});
console.log(res);
res.type('audio/mpeg');
readstream.pipe(res);
});
});
});
回答1:
In old-timey database lingo media objects are called BLOBS -- binary large objects. In Mongo they're handled with a subsystem known as gridfs. There's a nice npm module called gridfs-stream to make this easier.
An easy way to deliver media objects to browsers is to make them available behind URLs that look like https://example.com/audio/objectname.mp3
. And, they should be delivered with the appropriate Content-Type header for the codec in use (audio/mpeg
for MP3). Then the src tag can simply name the URL and you're rockin' and rollin'. The audio tag in the browser page looks something like this:
<audio controls src="/audio/objectname.mp3" ></audio>
So, if you want to deliver audio directly via express, you need a route with a parameter, something like
app.get('/audio/:filename', ...
Then the node program uses something like this not debugged!)
const mongo = require('mongodb');
const Grid = require('gridfs-stream');
...
const db = new mongo.Db('yourDatabaseName', new mongo.Server("host", 27017));
const gfs = Grid(db, mongo);
...
app.get('/audio/:filename', function (req, res) {
const readstream = gfs.createReadStream({filename: req.params.filename})
readstream.on('error', function (error) {
res.sendStatus(500)
})
res.type('audio/mpeg')
readstream.pipe(res)
});
This is cool because streams are cool: your node program doesn't need to slurp the whole audio file into RAM. Audio files can be large.
gridfs offers the mongofiles command line utility for loading files into gridfs.
But, all that being said: Most scalable media services use static media files delivered from file systems and/or content delivery networks. Servers like apache and nginx have many programmer years invested in making file delivery fast and efficient. The database holds the pathnames for the files in the CDN.
How to troubleshoot this kind of thing?
- Watch the browser's console log.
- Hit the media URL directly from a browser. See what you get. If it's empty, something's wrong with your retrieval code.
- In dev tools in the browser, look at the Network tab (in Google Chrome). Look for the media object, and examine what's going on.
回答2:
I think what you're looking for is a stream, so you can stream data from the server to the webpage directly without saving it. Node js comes with this functionality more of it from the documentation here https://nodejs.org/api/stream.html
来源:https://stackoverflow.com/questions/55230048/passing-audio-from-mongodb-to-audio-tag