On findOneAndUpdate check that item with parameter existing in array - javascript

I have model:
var UserSchema = new Schema({
name : {type: String, required: true},
devices : [
{ uuid : {type: String, required: true},
token : {type: String, required: true}
]
})
When user connects from another (new) device I want to push new device to devices array, otherwise, when user updates token, I need to update existing array item.
So, what I am doing:
User.findOneAndUpdate({name: 'John'}, {
$push: {devices : { uuid : '12345', token : 'TEST_TOKEN'}}
}, {safe: true, new : true}, function(err, user) {
console.log(err);
console.log(user);
});
I think that I need somehow check that device UUID does not exist in array, and if exist update token, otherwise create new device item and push to array
I already try to create uuid index with unique: true
{ uuid : {type: String, required: true, index : {unique: true}}
But this index sets to all collection. And if I have another user with same UUID, I cant add new.
How can I do what I want?

The solution is here, the problem was in that i didnt know how to update arrays in models by using findOneAndUpdate function.

Related

Mongoose findByIdAndUpdate method not incrementing document value

I am trying to update the like count of job posts in my application using the $inc operator and the findByIdAndUpdate method from Mongoose. The correct document is being retrieved and returned but the like count for the job post never moves up from 0 and no updates are performed in the database collection.
Below is the code I am currently using to perform the update.
Jobs.findByIdAndUpdate(req.params._id , { $inc: {likes: 1}} , {new: true})
.then((ret) => {
res.send(ret)
})
Job schema
const mongoose = require('mongoose');
let JobSchema = mongoose.Schema({
student_name: {
type: String,
required: true
},
subject: {
type: String,
required: true
},
grade: {
type: Number,
required: true
},
area: {
type: String,
required: true
},
desc: {
type: String,
required: true
},
accepted: {
type: Boolean,
required: true,
default: false
},
tutor_name: {
type: String,
required: false
},
} , {collection: 'jobs'});
let Job = mongoose.model('Job' , JobSchema);
module.exports = Job;
Any insight into what is preventing the update from performing would be greatly appreciated
I have tried using two queries, one to retrieve the current likes of a post and another to manually update the doc with the incremented value. I have tried nesting the queries using .then() statements and have also tried the updateOne() and findOneAndUpdate() methods as alternatives. I have tried experimenting with the $set and $inc operators in my queries to see if either of them perform the changes, but neither do.
I am expecting the incremented 'likes' value to be reflected in the database and for the updated job document to be returned and echoed back to the console.
Your schema is missing a likes field, which means Mongoose will remove it from queries/updates (since it doesn't match the schema). Make sure to add it:
likes: {
type: Number,
default: 0
}
Can you try something like this (adding [] around update):
Jobs.findByIdAndUpdate(req.params._id , [{ $inc: {likes: 1}}] , {new: true})
.then((ret) => {
res.send(ret)
})
EDITED:
Jobs.findByIdAndUpdate(req.params._id , [{ $set: {likes: "$likes"+1}}] , {new: true})
.then((ret) => {
res.send(ret)
})

Adding documents to a Many to Many relationship in Mongoose (MongoDB)

I have a User collection and a Task Collection. Many Users can have many Tasks, and Many Tasks can have many Users. The proper way I believe in doing this is the following models:
var UserSchema = new Schema({
id: ObjectId,
username: { type: String, required: true },
assignments: [ {type : mongoose.Schema.ObjectId, ref : 'Assignment'} ]
});
var TaskSchema = new Schema({
id: ObjectId,
title: { type: String, default: '' },
information: { type: String, default: '' },
assignments: [ {type : mongoose.Schema.ObjectId, ref : 'Assignment'} ]
});
var AssignmentSchema = new Schema({
id: ObjectId,
isCompleted: { type: Boolean, default: false },
completionDate: { type: Date, default: null },
tasks: [ {type : mongoose.Schema.ObjectId, ref : 'Task'} ],
users: [ {type : mongoose.Schema.ObjectId, ref : 'User'} ]
});
If the above models are correct, how do you insert a Task with multiple user assignments? I understand that you would create the Task document first to get its ObjectId, but after that would you just insert all of the assignments into the Assignment collection (with their proper Task and User objectId's) and thats it? Or would I have to insert all of the assignments then edit each individual User and Task to insert the AssignmentId into their assignments property.
I am sure there is a stack over flow question like this already, but I have not been able to find one. Any help is appreciated!
I believe you have the answer in your question.
Create a new task, capture the task id. Then find or create a new user, edit or add the task’s id, capture the user id. Add the user id to the task. Repeat for additional users.
I believe this is what you say in the final part of your question?
I don’t see why this cannot work.

Cast to ObjectId failed for value error in Mongoose findOne

I've been struggling with a weird exception and still confused about it after an hour.
CastError: Cast to ObjectId failed for value "pedrammarandi#gmail.com"
at path "_id" for model "Account"
I'm trying to retrieve an Account via email address. Here is my query
export async function getPendingRecipients(user_id, email_address) {
const account = await Account
.find({email: email_address})
.exec();
return true;
}
This is my Schema object
const userGmailSchema = new Schema({
id: {
type: String,
unique: true
},
displayName: String,
image: Object,
accessToken: String,
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
refreshToken: {
type: String,
default: null
},
email: {
type: String,
unique: true
},
emails: [
{
type: Schema.Types.ObjectId,
ref: 'Emails'
}
]
});
I'm not sure, but I guess the problem is you wrote an id field.
In MongoDB, the "primary key" is _id field, which is an ObjectId object (actually it's a 12-byte-value), and in mongoose, id is a virtual getter of _id, easily said, id is an alias of _id.
(A little different is that, _id returns ObjectId, id returns String version of _id.)
By default, mongoose manage _id field automatically, so commonly we should not write anything about id in schema.
If your id is for something like primary key ID in SQL DB, just remove it from mongoose schema. If it's means something else in your app, try to add an option:
const userGmailSchema = new Schema({
// your schemas here
},
{
{ id: false } // disable the virtual getter
})
or rename it.
http://mongoosejs.com/docs/guide.html#id
Hope this helps.

Mongoose create multidimensional array

What way would I go to save 40 different types of crimes, that each have and id and chance?
How would I get the ids, chance and update them?
What I got so far:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var crime_modelSchema = new Schema({
userid : String,
crimes: [
{
id: {type: Number, default: 1},
chance: { type: Number, default: 50}
}
],
ip: String,
time: Number,
});
module.exports = mongoose.model('crime_model', crime_modelSchema);
Is this the way to go or am I far?
For specific user:
db.crime_model.update({userid: user_id_you_want, "crimes.id": crimes_id_you want}, {$set: {"crimes.$.chance": 'update chnace'}});
For all user with specific crime id
db.crime_model.update({"crimes.id": crimes_id_you want}, {$set: {"crimes.$.chance": 'update chnace'}}, {multi: true});
Get id, chance you can directly retrieve the crime
db.crime_model.find({}, {crimes: 1})

Grab object from MongoDB but limit number of items pulled from array

My API currently has a route for Getting an event from my MongoDB database based on event_id. This works fine. However, I have a 'photos' array within this event object that is growing (currently over 3,000 objects within this array).
I want to pass a limit parameter to limit the number of results pulled from this array, but cannot figure out how. Below is my current node route and mongoDB schema:
route:
// get event by _id
app.get('/api/events/:event_id', function(req, res) {
// use mongoose to get event
Event.findOne({object_id: req.params.event_id}, function(err, event) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err)
if (req.params.limit >= 0) {
// res.jsonp(event) with photos array limited to req.params.limit
}
res.jsonp(event); // return event in JSON format
});
});
schema:
var eventSchema = new Schema({
event: String,
city: String,
state: String,
date: String,
start: String,
end: String,
dateState: String,
radius: String,
team_1: String,
team_2: String,
object_id: String,
longitude: String,
latitude: String,
cover: {
img: String,
username: String
},
photos: []
})
Don't have a constantly growing array field. It's not good for performance because MongoDB (well, if <= 2.6/using mmap) will be moving the document around when it grows outside of the space allocated for it by the storage engine, causing performance problems. You should change your schema to avoid an array like this, but I can't really say more about how you should do it because I don't know much about your use case.
There is a way to limit the number of array elements returned in a find query though, using $slice projection.
> db.test.drop()
> db.test.insert({ "_id" : 0, "x" : [0, 1, 2, 3, 4] })
> db.test.find({ "_id" : 0 }, { "x" : { "$slice" : 2 } })
{ "_id" : 0, "x" : [0, 1] }
Event.findOne({object_id: req.params.event_id})
.limit(10)
.exec(function(e,doc){
...
});
Edit
Or if you have ref on the photo... you can populate the doc array of referenced id with limit option. Hope it helps :) All abount population
.find(...)
.populate({
path: 'photos',
options: { limit: 5 }
})
.exec(...)
Schema
var eventSchema = new Schema({
event: String,
city: String,
state: String,
...
photos: [{ type:String, ref:'pictureSchema' }]
}
var pictureSchema = new Schema({
name : {type:String},
url : {type:String},
...
}
In photos array than you just put id of the pictures doc, when you populate the photos array it will put pictureSceham doc insted of _id.

Categories

Resources