I want to fetch data from database by _id and ownerId so I gave OR condition, but getting this error
Argument passed in must be a Buffer or string of 12 bytes or a string of 24 hex characters
My code as follow
var ObjectId = require("mongodb").ObjectId;
const getDetailById = async (req, res) => {
const { id } = req.params;
try {
let detail = await Task.find(
{ $or: [{ ownerId: id }, { _id: ObjectId(id) }] }
).populate("shop");
} catch (err) {
sendError(401, "Cannot get detail by given id", err.message, req, res);
}
};
here I can get data from database by passing _id which is 24 character but when I tried to fetch data by ownerId its shows me this error:
Argument passed in must be a Buffer or string of 12 bytes or a string of 24 hex characters
My output look like this
{
"_id": "61483aa5e6dcd5bb6b2c9c58",
"ownerId": "b0jytaonktsc5ghf",
"ownerName": "check demo",
"ownerDescription": "Testing purpose",
"shop": {
"_id": "61483aa5e6dcd5bb6b2c9c55",
"shopName": "Aakash",
"shopPlace": "Mumbai",
"__v": 0
},
"createdAt": "2021-09-20T07:39:17.528Z",
"updatedAt": "2021-09-20T07:39:17.528Z",
"__v": 0
},
and this is my Schema:
const mongoose = require("mongoose");
const uniqid = require("uniqid");
const ownerSchema = new mongoose.Schema(
{
ownerId: {
type: String,
default: uniqid(),
unique: true,
},
OwnerName: {
type: String,
},
taskTag: [
{
type: String,
},
],
onwerDescription: {
type: String,
},
shop: {
type: mongoose.Schema.Types.ObjectId,
ref: "peoples",
default: null,
},
},
{ timestamps: true }
);
const owner = mongoose.model("task", ownerSchema);
module.exports = owner;
The problem is the call of ObjectId(id) because it can not handle the input of an ownerId string as soon as you are passing the ownerId.
The cleanest solution (in my opinion) would be to change the type of ownerId to ObjectId as well:
const mongoose = require("mongoose");
const uniqid = require("uniqid");
const ownerSchema = new mongoose.Schema(
{
ownerId: {
type: mongoose.Schema.Types.ObjectId,
default: mongoose.ObjectId(),
unique: true,
},
OwnerName: {
type: String,
},
...
Or to handle the different inputs like:
var ObjectId = require("mongodb").ObjectId;
const getDetailById = async (req, res) => {
const { id } = req.params;
let filter = [{ ownerId: id }]
try {
const _id = ObjectId(id);
filter.push({ _id })
} catch () {
// Do nothing
}
try {
let detail = await Task.find(
{ $or: filter }
).populate("shop");
} catch (err) {
sendError(401, "Cannot get detail by given id", err.message, req, res);
}
};
PS: Do not forget to perform some input validation! Never trust user input ;)
ObjectId has exactly 24 hex characters or string of 12 bytesuniqid library that you use for generating ownerId generates 18 byte unique idAs you see the format of these 2 is not compatible. So what happened is this:
uniqid() generated$or will try to generate ObjectId based on that value, and since the format is not compatible with ObjectId format, it will throw the error that it is invalid format of the ObjectIdYou can change the uniqid library with the native Node crypto library to generate 24 hex characters string of 12 bytes, that will be compatible with ObjectId format. Since it is native package, you don't need to install it, you can just import it and use it. Now you can also remove uniqid package from you project and decrease the number of dependencies.
const mongoose = require("mongoose");
const crypto = require("crypto");
const ownerSchema = new mongoose.Schema(
{
ownerId: {
type: String,
default: crypto.randomBytes(12).toString('hex'),
unique: true
},
...
);