Hello,
I am using the sharp npm module to resize a png image that I am saving into a mongo collection.
The sharp module returns a promise, please see my code.
I make 2 queries to the db, one to update the doc and another when the sharp module promise resolves to update the image.
How can I make it in one call?
Thanks
export const insertMeme = new ValidatedMethod({
name: 'memes.insert',
validate: memeSchema.validator({ clean: true, filter: true }),
run(document) {
const _id = Memes.insert(document);
if (Meteor.isServer) {
const base64string = document.image.replace('data:image/png;base64,', '');
const sharp = require('sharp');
sharp(Buffer.from(base64string, 'base64'))
.png({ compressionLevel: 9, adaptiveFiltering: true, force: true })
.resize({ width: 500 })
.toBuffer()
.then(buffer => {
document.image = 'data:image/png;base64,' + buffer.toString('base64');
Memes.update(document._id, {
$set: document
});
})
.catch(err => {
console.error(err);
});
}
return _id;
},
});
I suggest doing it this way:
export const insertMeme = new ValidatedMethod({
name: 'memes.insert',
validate: memeSchema.validator({ clean: true, filter: true }),
async run(document) {
const _id = Memes.insert(document);
if (Meteor.isServer) {
const base64string = document.image.replace('data:image/png;base64,', '');
const sharp = require('sharp');
const image = await sharp(Buffer.from(base64string, 'base64'))
.png({ compressionLevel: 9, adaptiveFiltering: true, force: true })
.resize({ width: 500 })
.toBuffer();
document.image = 'data:image/png;base64,' + buffer.toString('base64');
Memes.update(_id, {
$set: document
});
}
return _id;
},
});
But I also suggest you run this method only on the server. Still there is nothing wrong in doing it this way.
Hhope this helps
1 Like
Thanks for the reply, your code make sense.
I tried async/await in meteor but it doesn’t work.
I am missing something.
async/await in Meteor is basically async/await in JavaSript. If you want to call a validated-method as a promise take a look at https://github.com/didericis/callpromise-mixin/.
Rob, it is the same from pmogollon.
Looking at the code from @pmogollon, which I think has a typo, along with your original request to write to the db with one call, can you try this:
export const insertMeme = new ValidatedMethod({
name: 'memes.insert',
validate: memeSchema.validator({ clean: true, filter: true }),
async run(document) {
if (Meteor.isServer) {
const base64string = document.image.replace('data:image/png;base64,', '');
const sharp = require('sharp');
const image = await sharp(Buffer.from(base64string, 'base64'))
.png({ compressionLevel: 9, adaptiveFiltering: true, force: true })
.resize({ width: 500 })
.toBuffer();
document.image = 'data:image/png;base64,' + image.toString('base64');
const _id = Memes.insert(document);
}
return _id;
},
});
Incidentally, using document
is a bit risky in the browser, as it’s reserved for the HTML document. Better to use doc
, maybe.
1 Like
Thank you @robfallows and @pmogollon
pmogollon code actually works, maybe yesterday I was too tired to notice.
The following code works for me and it is using document as variable,
I think it is not a problem because it is a function argument.
Only one call to the db.
export const insertMeme = new ValidatedMethod({
name: 'memes.insert',
validate: memeSchema.validator({ clean: true, filter: true }),
async run(document) {
if (Meteor.isServer) {
const base64string = document.image.replace('data:image/png;base64,', '');
const sharp = require('sharp');
const buffer = await sharp(Buffer.from(base64string, 'base64'))
.png({ compressionLevel: 9, adaptiveFiltering: true, force: true })
.resize({ width: 500 })
.toBuffer();
document.image = 'data:image/png;base64,' + buffer.toString('base64');
}
return Memes.insert(document);
},
});
@robfallows @pmogollon @softwarerero
The above code works with async await but now I can not throw exceptions from the async function.
I need to throw some exceptions that are display as error in red on the UI page.
How can I throw exceptions from the async function, the following does not work
I get the following error:
1 Uncaught (in promise) {error: “validation-error”, details: Array(1)}
if (!(/\b______\b/g).test(document.topText) && !(/\b______\b/g).test(document.bottomText)) {
throw {
error: 'validation-error',
details: [{
type: 'blankRequired',
name: 'topText',
}]
};
}
You need to throw new Meteor.Error
to ensure a server error is sent to the client.
2 Likes