Where & Count cant be implemented together in Loopback 4 - mongodb

I am implementing an API that can take out all the data where user_id: user_id
but it is not working please help me to implement the same.
here is my code of Follow_api controller:
#get('/follow-masters/count/{id}')
#response(200, {
description: 'FollowMaster model count',
content: {'application/json': {schema: CountSchema}},
})
async findCount(
#param.path.string('user_id') user_id: string,
#param.where(FollowMaster) where?: Where<FollowMaster>,
): Promise<Count> {
return this.followMasterRepository.count();
}

Solved using this code:
#get('/follow-masters/count/{user_id}')
#response(200, {
description: 'FollowMaster model count',
content: {'application/json': {
schema: FollowMaster
}
},
})
async findCount(
#param.path.string('user_id') user_id: string,
#param.where(FollowMaster) where?: Where<FollowMaster>,
): Promise<NonVoid> {
return this.followMasterRepository.find({
where: {
user_id: user_id, ...where,
},
});
}

Related

Recursive mongoose schema does not result in correct object stores

I have a recursive model schema defined in a schema which uses the add() method in the Schema class to incrementally build the schema. It seems to build the paths correctly as shown when I print out the paths. However, when I use the Model defined to store the object in the database, it is missing the inner BNode. Here is a definition of the schema:
import mongoose from 'mongoose';
const BNodeSchema = new mongoose.Schema({
bValue: { type: [Number] },
id: String,
})
const RValue = {
rId: String,
value: Number
}
const ANodeSchema = new mongoose.Schema({
type: {
id: String,
rValues: {
type: Map,
of: RValue
},
}
})
const QuestSchema = new mongoose.Schema({
type: {
_id: { type: String, },
aNode: ANodeSchema,
bNodes: [BNodeSchema],
url: {
type: String
},
id: {
type: String
}
},
},
{ id: false }
)
ANodeSchema.add({ quest: QuestSchema });
const QuestNodeSchema = new mongoose.Schema({
_id: { type: String, unique: true },
quests: { type: [QuestSchema] },
}, {
id: false
})
export const QuestModel = mongoose.model('QuestModel', QuestNodeSchema);
QuestNodeSchema.eachPath(function(path:any) {
console.log(path);
});
{
_id: 12223,
quests:[
{
id: 'Quest-111-111' ,
aNode: {
id: 'A222222',
rValues: {
rId: 'RR1222',
value: 44422
},
quest:{
url: 'https://deptio-opcom',
id: '22222-QST',
bNodes:[{
bValue: 'B22190',
value: 22085
}]
}
}
}
]
}
I have included a sample of the json I am storing in the database. I use a class, not included for brevity to create the equivalent JSON object in the final format to be stored. My feeling is that there is something not quite right with my schema definition. I would be most grateful if someone could help me figure out what I am missing in my definition. Thanks a lot

how to delete a nested object within an array in mongoose and express?

I have a schema that looks like this:
const pickupGameSchema = new mongoose.Schema(
{
id: String,
userAdminFirst: String,
userAdminLast: String,
userAdminID: String,
userAttending: [{
id: String,
firstName: String,
lastName: String,
address: String,
}]
}
)
And a delete route that looks like this:
router.delete(':id/players/:playerId', async (req, res) => {
res.send('hello');
try {
const result = await pickupGame.updateOne(
{ '_id': req.params.pickId, 'userAttending._id': req.params.playerId },
{
$pull: { 'userAttending': { _id: req.params.playerId } },
},
);
res.send(result);
} catch (err) {
console.log(err);
res.status(500).send('Something went wrong');
}
},
);
I need my route to delete a specific user within the userAttending array. What is the best way to do this?

mongoose select query with count from other collections

I am working with node(express) with mongoose and I have two collections,
Users
Comments
I added the sample Schema(added few fields only)
const UserSchema = mongoose.Schema({
name: String,
email: String,
});
const CommentsSchema = mongoose.Schema({
comments: String,
user_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
text: String,
});
So I trying to fetch the users list and no of comments count based on user..
Expecting output like below:
data = [
{
name: 'abcd',
email: 'aa#test.com',
commentsCount: 5
},
{
name: 'xxx',
email: 'xx#test.com',
commentsCount: 3
}
]
I am not sure how to get the results, because we don;t have ref in user table..
userModel.find({}).exec((err, users) => {
if (err) {
res.send(err);
return;
}
users.forEach(function(user){
commentsModel.countDocuments({user_id: users._id}).exec((err, count) => {
if(!err){
user.commentsCount = count;
}
})
});
console.log('users', users)
});
Can you anyone please help to fix, I needs to list out the users and count of comments

Push ObjectId to nested array in Mongoose

(Basic library CRUD application)
I am trying to create a document containing some global data about a given book, and then within a User document, add the ObjectId of the newly-created book to an array containing all books belonging to that user.
I have three data models in my application:
var userSchema = new mongoose.Schema({
name: String,
password: String,
email: String,
books: [BookInstanceSchema],
shelves: [String]
});
var bookSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
author: {
type: String,
required: true
},
description: String,
pageCount: Number,
ISBN: String,
googleID: String,
thumbnail: String,
publisher: String,
published: String,
});
var BookInstanceSchema = new mongoose.Schema({
bookId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Book'
},
userReview: String,
userRating: {
type: Number,
get: v => Math.round(v),
set: v => Math.round(v),
min: 0,
max: 4,
default: 0
},
shelf: String
});
The User model contains a nested array of BookInstances, which contain user-specific data such as ratings or reviews for a given book. A bookInstance in turn contains a reference to the global data for a book, to avoid duplicating data that isn't specific to any user.
What I'm trying to do is first save the global data for a book (thus generating an _id), and when done, save a bookInstance containing that _id in a given user's array of books:
router.post('/save/:id', function(req, res) {
var url = encodeurl('https://www.googleapis.com/books/v1/volumes/' + req.params.id);
request(url, function(err, response, data) {
parsedData = JSON.parse(data);
var newBook = {
title: parsedData.volumeInfo.title,
author: parsedData.volumeInfo.authors[0],
description: parsedData.volumeInfo.description,
pageCount: parsedData.volumeInfo.pageCount,
ISBN: parsedData.volumeInfo.description,
googleID: parsedData.id,
publisher: parsedData.volumeInfo.publisher,
published: parsedData.volumeInfo.publishedDate,
thumbnail: parsedData.volumeInfo.imageLinks.thumbnail
};
Book.create(newBook, function(err, newBook) {
if (err) {
console.log(err);
}
else {
console.log(newBook._id);
console.log(mongoose.Types.ObjectId.isValid(newbook._id));
User.findByIdAndUpdate(req.session.id, {
$push: {
"books": {
bookId: newBook._id,
userRating: 0,
userReview: ''
}
}
},
{
upsert: true
},
function(err, data){
if(err) {
console.log(err);
}
else {
res.redirect('/');
}
});
}
});
});
});
I'm getting the error:
message: 'Cast to ObjectId failed for value "hjhHy8TcIQ6lOjHRJZ12LPU1B0AySrS0" at path "_id" for model "User"',
name: 'CastError',
stringValue: '"hjhHy8TcIQ6lOjHRJZ12LPU1B0AySrS0"',
kind: 'ObjectId',
value: 'hjhHy8TcIQ6lOjHRJZ12LPU1B0AySrS0',
path: '_id',
reason: undefined,
Every time, the value in the error (in this case, jhHy8T...) is different than the newBook._id I'm attempting to push into the array:
console.log(newBook._id); // 5a120272d4201d4399e465f5
console.log(mongoose.Types.ObjectId.isValid(newBook._id)); // true
It seems to me something is wrong with my User update statement:
User.findByIdAndUpdate(req.session.id, {
$push: {
"books": {
bookId: newBook._id,
userRating: 0,
userReview: ''
}
}...
Any help or suggestions on how to better organize my data are appreciated. Thanks!

mongodb: only update document if is not updated

I have this function. Allow take a service only is not taken:
is taken only if the available param is true.
function takeService(req, res) {
var serviceId = req.params.id;
var driverId = req.body.driverId;
Service.findById(serviceId, (err, service) =>{
if (!err) {
if (!service) {
res.status(404).send({message: 'Not found'});
} else {
if (service.available === false ) {
res.status(409).send({message: 'The service is taken'});
} else {
Service.findByIdAndUpdate(serviceId, {
driverId,
status: 1,
available: false
}, (err, serviceUpdated) =>{
if (!err && serviceUpdated) {
res.status(200).send({message: "tomado"});
}
});
}
}
}
});
}
Schemas:
var ServiceSchema = Schema({
clientId: {
type: String,
ref: 'Client'
},
available: Boolean,
routeId: {
type: String,
ref: 'Route'
},
date: Date,
radius: Number,
driverId: {
type: String,
ref: 'Driver'
},
status: Number,
time: String,
createdTime: Number,
rateId: {
type: String,
ref: 'Rate'
}
});
var DriverSchema = Schema({
name: String,
surname: String,
username: String,
password: String,
status: { type: Number, default: 0 },
oneSignalId: String,
plate: String,
make: String,
year: String,
model: String,
groupId: [{
type: String,
ref: 'DriverGroup'
}],
unit: String,
telephone: String
});
The problem is when two devices call to this function, in some cases both find the document and check if is available and then both update the same document. I am looking a some validation in the schema for autocheck this property.
If I understand the problem correctly, the main issue is that two devices may think that a service is still available.
The ultimate cause of this is that there's a race condition between findById and findByIdAndUpdate: between those two calls, there's a window of time in which another request can change the document in the database.
To fix this, you can use the atomic findAndModify command, which Mongoose exposes as (amongst others) Model#findOneAndUpdate.
Your code would become something like this:
function takeService(req, res) {
var serviceId = req.params.id;
var driverId = req.body.driverId;
Service.findOneAndUpdate({
_id : serviceId,
available : true
}, {
driverId : driverId,
status : 1,
available : false,
}, (err, service) => {
if (err) {
return res.status(500);
} else if (! service) {
return res.status(409).send({message: 'The service is taken'});
} else {
return res.status(200).send({message: "tomado"});
}
});
}
There are a few differences with your original code that you should be aware of:
you can't distinguish between a service not existing (invalid/unknown serviceId) and a service that is not available anymore; in both cases, the update will yield no result and a 409 response is sent back;
findOneAndUpdate will return the old document, before it was updated. If you want to receive the updated document, pass the new option in the query:
Service.findOneAndUpdate({ ... }, { ... }, { new : true }, (err, service) => { ... })
I added an error handler in there, that sends back a 500 ("Internal Server Error") response.