Is there a solution when mongodb query parameter null or exists? - node.js

I'm trying to make get customer & store from mongodb use mongoose Model,
getCustomer Function parameter are customer and store, But sometimes store parameter is null || undefined
// Mongoose Model
const Customer = require("../models")
// Find customer && Store
const getCustomer = async (customer, store) => {
const result = await Customer.aggregate([
{
$match: {
customerId: customer.id,
storeId: store.id,
},
},
]);
return result;
};
So this $match query in aggregate is return Error, Because store.id is not found.
Can you tell me what query I should use if store data is passed unconditionally?

Pass the store.id conditionally, like this:
const getCustomer = async (customer, store) => {
const result = await Customer.aggregate([
{
$match: {
customerId: customer.id,
...(store && store.id ? { storeId: store.id } : {})
},
},
]);
return result;
};

Related

Getting an {"message":"Invalid update pipeline operator: \"_id\""} error

I am trying to update two rows in my players table based on the id. I am trying to use the updateMany method where id can be found in an array of id's but I am getting the {"message":"Invalid update pipeline operator: \"_id\""} error. I checked the array to make sure it is valid id's. Here is my code
const winningTeam = asyncHandler(async (req, res) => {
req.body.forEach((element) => {
element.wins += 1;
element.lastPlayed = Date.now();
element.percentage = (element.wins / (element.wins + element.wins)) * 1000;
});
let usersId = [];
usersId.push(req.body[0]._id);
if (req.body.length === 2) {
usersId.push(req.body[1]._id);
}
const player = await Player.updateMany({ _id: { $in: usersId } }, req.body);
if (player) {
res.status(200).json(player);
} else {
res.status(400);
throw new Error("Invalid Data");
}
});
You should use $set property for the update parameter. I'm not sure about the structure of your req.body but it should be something like this:
Player.updateMany({ _id: { $in: usersId } }, {$set: req.body});
instead of this:
Player.updateMany({ _id: { $in: usersId } }, req.body);
Take a look at docs for updateMany

Updating a nested objects in Mongoose

I have the following express route:
const updateSnapshot = async (req, res) => {
const accountId = req.body.account_id;
if (!accountId) {
return fail(res, 'account id is missing', 400);
}
try {
const account = await Account
.findOne({ _id: accountId})
.populate({
path: 'snapshot',
model: 'Snapshot'
});
// I want to update these fields in snapshot
const snapshot = {
friends_count: data.friends_count,
updated_date: new Date()
};
account.snapshot.friends_count = snapshot.friends_count;
account.snapshot.updated_date = snapshot.updated_date;
await account.save();
return success(res, snapshot);
} catch(error) {
fail(res, error.message, 500);
}
};
I want to update the nested object snapshot (just the fields friends_count and update_date) however when I check the database it seems to have not work. What am I doing wrong here?
const updateSnapshot = (req, res) => {
const accountId = req.body.account_id;
if (!accountId) {
return fail(res, 'account id is missing', 400);
};
Account
.findOneAndUpdate({ _id: accountId }, {
$set: {
snapshot: {
friends_count: data.friends_count,
updated_date: new Date()
}
}
}, {
new: true
})
.then(account => {
if(!account) {
return fail(res, "Account not found", 404);
} else {
return success(res, account);
};
})
.catch(err => {
return fail(res, error.message, 500);
});
};
Here we're using the findOneAndUpdate method and promises to find and update the document in one operation.
findOneAndUpdate takes the query criteria as the first parameter, the second parameter updates values specified in the object (we're using the $set operator to update specific values of the snapshot object), and the three parameter is an object that defines the operation's options (new is set to true to return the newly updated object).
Note: $set will replace the entire snapshot object so if there are other properties inside the snapshot object, they will need to be included inside the $set object.

Sequelize how to get all data if there is no query string passed

I'm pretty new to Sequelize.
I'm trying to create a handler to get all playlists in my database.
This is what I want to do:
If there is a query string then it should return the result based on that query.
If there is no query string passed then it should return all my playlists.
This is my playlist model:
const Playlist = db.define("playlist", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: Sequelize.STRING,
unique: true,
},
});
Here is my handler:
exports.getPlaylists = async (req, res) => {
try {
const { name } = req.query;
console.log(name); // this prints the name
const result = await Playlist.findAll({
where: {
name:
name === undefined ? {} : { $like: `%${name}%` },
},
});
if (result) {
res.status(200).send(result);
} else {
response.status(404).send("No Playlists found");
}
} catch (error) {
res.status(500).send(`Internal server error: ${error}`);
}
};
This works well if I passed a name in the query. but If I didn't pass any query string. It returns an empty array.
$like is an alias for Sequelize.Op.like
What should I put instead of the empty object?
I checked this question How get all data if field in query string is empty Node and Sequelize with Postgres but the proposed solutions didn't work with me
Create a filter object based on the condition. If you pass empty object to where, it won't apply that in the query.
exports.getPlaylists = async (req, res) => {
try {
const { name } = req.query;
const filters = {};
if (name)
filters.name = {
[Op.like]: `${name}%`, // you can also use $like if you are using older version of sequelize
}
const result = await Playlist.findAll({
where: filters,
});
if (result) {
res.status(200).send(result);
} else {
response.status(404).send("No Playlists found");
}
} catch (error) {
res.status(500).send(`Internal server error: ${error}`);
}
};
This way you can prepare complex filters based on other query strings.

how to query mongodb based on object to get documents that contains one or more equal properties (Search)

Im trying to figure out how to Post a search object to mongo, and find all documents that matches one or more properties stated in the search object.
eg if i have post a json object as this:
// searchObject
{
"kind": "employee"
"name": "casper",
"email": "daniel#mail.com"
}
i want to get all documents that contains "name": "casper"or "email":"daniel#mail.com"or both from the employee collection.
this is what i have so far. but i dont know how to loop through my properties.
router.post('/search', async (ctx) => {
const searchObject = Object.assign(ctx.request.body);
const collection = searchObject.kind
const result = await store[collection].find({
$and: [{ searchObject }]
})
console.log('result', result)
})
Try this:
router.post('/search', async ctx => {
const { kind, ...searchObject } = ctx.request.body;
const collection = searchObject.kind;
const conditions = Object.keys(searchObject).reduce((acc, key) => {
acc.push({ [key]: searchObject[key] });
return acc;
}, []);
const result = await store[collection].find({
$or: conditions,
});
console.log('result', result);
});
add if (key !== "kind") condition in reduce function
router.post('/search', async ctx => {
const searchObject = ctx.request.body;
const collection = searchObject.kind;
const conditions = Object.keys(searchObject).reduce((acc, key) => {
if (key !== "kind") acc.push({ [key]: searchObject[key] });
return acc;
}, []);
const result = await store[collection].find({
$or: conditions,
});
console.log('result', result);
});

Paginated results in mongoose with filters on reference document

I have a user and post document as follow:
user: {
"name": "Test",
interests: [
"Sports",
"Movies",
"Running"
]
}
post: {
"title": "testing",
"author": ObjectId(32432141234321411) // random hash
}
I want to query posts and fetch all those posts with author have "sports", "Running" as interests and this will be a paginated query.
How can I do so in mongoose and if not what alternative shall I use ?
Pagination using limit and skip
var limit = 5;
var page = 0; // 1,2,3,4
return Model.find({
/* Some query */
})
.limit(limit)
.skip(limit * page)
.exec().then((data) => {
console.log(data);
});
Try this
const findUser = (interests) => {
return User.find({
interests: {
$in: interests
}
}).exec();
};
const findPost = (query, page = 0) => {
const limit = 5;
return Model.find(query)
.limit(limit)
.skip(limit * page)
.exec();
};
var execute = async () => {
const users = await findUser(["Sports", "Movies", ]);
users.forEach(user => {
user.post = await findPost({
"post.author": user._id
});
});
return users;
}
I used following approach though giving answer with async/await approach but I actually used it using promises.
const fetchPosts = async (req, res) => {
//First find users having those interests.
const users = await User.find({
interests: {
"$in": ["Sports", "Movies"]
}
})
.select('_id')
.exec();
// map over array of objects to get array of ids
const userIds = users.map(u => u._id);
// Then run an in filter on Post collection against author and
//userIds
const posts = await Post.find({
author: {
"$in": [userIds]
}
})
.limit(15)
.skip(0)
.exec();
}

Resources