Removing an objectID of an object in an array with Mongoose - node.js

I have the following in my clan scheme
var ClanScheme = new mongoose.Schema
({
name: {type: String, unique: true},
members:
[
{
user: {type: mongoose.Schema.Types.ObjectId, ref:'User', unique: true},
wins: {type: Number, default: 0},
losses: {type: Number, default: 0}
}
],
How do I remove a user from the clan? I've tried a few methods this looking like the least code:
clan.members.remove({'user':userObj._id});
clan.save(function(err)
It seems to run, but the user sticks in the document..
Clan
{ _id: 55e5e8d017e055495dcc3643,
name: 'DBz',
__v: 9,
rating: 1000,
losses: 0,
wins: 0,
rank: 0,
members:
[ { user: [Object],
_id: 55e5e8d017e055495dcc3644,
losses: 0,
wins: 0 },
{ user: [Object],
_id: 55e5eb0f17e055495dcc3645, //<< 55e4ac0340f964d52f8e7fb7
losses: 0,
wins: 0 } ] }
User
{ _id: 55e4ac0340f964d52f8e7fb7,
facebookid: '999',
name: 'Joe Blogs',
__v: 0,
lastDevice: { device: 'Desktop', id: 'adsbr2fjui33emk9p6gtnfrulv' },
multiplayer:
{ clanid: 55e5e8d017e055495dcc3643,
powers: [],
world_commander: 0,
losses: 0,
wins: 0,
clanname: 'DBz',
rating: 1000,
rank: 0,
username: 'Joe' },
saveDataSeed: 40wq211,
saveData: 'yuV2hVJA00zYGm'}

Use a filter function and save.
clan.members = clan.members.filter(function(member){
return String(member.user._id) !== String(userObj._id);
});
clan.markModified('members');
clan.save(function(err)

Related

Why does my GraphQL/Apollo mutation fail?

This is how the Apollo query is defined:
const createUser = gql`
mutation(
$username: String!,
$email: String!,
$password: String!,
$time_created: String!,
$time_played: Int!,
$verified: Boolean!,
$type_user: Boolean!,
$userLevel: UserLevelInput!,
$ranks: RanksInput!,
$pvp: PvpInput!
){
createUser(
username: $username,
email: $email,
password: $password,
time_created: $time_created,
time_played: $time_played,
verified: $verified,
type_user: $type_user,
userLevel: $userLevel,
ranks: $ranks,
pvp: $pvp
){
username
email
password
}
}
`;
My schema:
const userSchema = new Schema({
username: String,
email: String,
password: String,
time_created: Date,
time_played: Number,
verified: Boolean,
type_user: Boolean,
userLevel: {
lidUnlocked: Number,
gidUnlocked: Number,
},
ranks: {
level: [
{
level: Number,
avgTime: Number,
rank: Number,
group: [
{
group: Number,
time: Number,
rank: Number,
},
],
},
],
},
pvp: {
points: Number,
rank: Number,
},
});
How I'm making the request:
const handleSubmit = (e) => {
e.preventDefault();
addUser({
variables: {
username: input.username,
email: input.email,
password: input.password,
time_created: Date.now(),
time_played: 0,
verified: false,
type_user: false,
userLevel: {
lidUnlocked: 1,
gidUnlocked: 1
},
ranks: {
level: [{
level: 1,
avgTime: 0,
rank: 0,
group: [{
group: 1,
time: 0,
rank: 0
}]
}]
},
pvp: {
points: 0,
rank: 0,
}
}
})
}
UserLevelInput, RanksInput and PvpInput:
const UserLevelInputType = new GraphQLInputObjectType({
name: "UserLevelInput",
fields: () => ({
lidUnlocked: { type: GraphQLInt },
gidUnlocked: { type: GraphQLInt },
}),
});
const RanksInputType = new GraphQLInputObjectType({
name: "RanksInput",
fields: () => ({
level: { type: new GraphQLList(LevelInputType) },
}),
});
const LevelInputType = new GraphQLInputObjectType({
name: "LevelInput",
fields: () => ({
level: { type: GraphQLInt },
avgTime: { type: GraphQLInt },
rank: { type: GraphQLInt },
group: { type: new GraphQLList(GroupInputType) },
}),
});
const GroupInputType = new GraphQLInputObjectType({
name: "GroupInput",
fields: () => ({
group: { type: GraphQLInt },
time: { type: GraphQLInt },
rank: { type: GraphQLInt },
}),
});
const PvpInputType = new GraphQLInputObjectType({
name: "PvpInput",
fields: () => ({
points: { type: GraphQLInt },
rank: { type: GraphQLInt },
}),
});
If i make this mutation on localhost:5005/graphql it works as intended:
mutation{
createUser(
username:"babadany2999",
email:"babadany2999#gmail.com",
password:"Immboold1",
time_created:"1645738406658",
time_played: 0,
verified: false,
type_user: false,
userLevel:{
lidUnlocked: 1,
gidUnlocked: 1
},
ranks: {
level: [{
level: 1,
avgTime: 0,
rank: 0,
group:[{
group: 1,
time: 0,
rank: 0
}]
}]
},
pvp: {
points: 0,
rank: 0
}
), {
username
email
password
}
}
Also if I make the request(with the code not in /graphql) and then check out Apollo Dev tools for that particular mutation, I get that the Int, UserLevelInput, RanksInput and PpvInput types are not known.
Apollo Dev Tools type unknown
For anyone encountering the same problem, I managed to "fix" it by creating constants of the complex objects and simply setting the default to those constants in the mongoose table and not giving that as input to apollo.
username: String,
email: String,
password: String,
time_created: {
type: Date,
default: new Date()
},
time_played: {
type: Number,
default: 0
},
type_user: {
type: Boolean,
default: false
},
verified: {
type: Boolean,
default: false
},
userLevel: {
lidUnlocked: Number,
gidUnlocked: Number
},
ranks: {
type: Object,
default: ranks
},
pvp: {
points: {
type: Number,
default: 0
},
rank: Number
}
})
And part of the constant(it's very long but it has the same structure until the end):
const ranks= {
level: [
{
level: 1,
group: [
{ group: 1, unlocked: true, time: 0, rank: 0 },
{ group: 2, unlocked: false, time: 0, rank: 0 },
{ group: 3, unlocked: false, time: 0, rank: 0 },
{ group: 4, unlocked: false, time: 0, rank: 0 },
{ group: 5, unlocked: false, time: 0, rank: 0 },
{ group: 6, unlocked: false, time: 0, rank: 0 },
{ group: 7, unlocked: false, time: 0, rank: 0 },
{ group: 8, unlocked: false, time: 0, rank: 0 },
{ group: 9, unlocked: false, time: 0, rank: 0 },
{ group: 10, unlocked: false, time: 0, rank: 0 },
{ group: 11, unlocked: false, time: 0, rank: 0 },
{ group: 12, unlocked: false, time: 0, rank: 0 },
{ group: 13, unlocked: false, time: 0, rank: 0 },
],
unlocked: true,
avgTime: 0,
rank: 0,
},

How to get the total number of occurences of a specific item in every document's array element

I am implementing favoriting/unfavoriting functionality to my express app but I have a problem on how to count the the total number the post has been favorited.
Assuming I have this Schema for Recipe
RecipeSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
maxlength: 30
},
description: {
type: String,
default: ''
},
favoritesCount: {
type: Number,
default: 0
}
})
And Schema for User
const UserSchema = new mongoose.Schema({
username: {
type: String,
minlength: 8,
required: true,
unique: true
},
fullname: {
type: String,
maxlength: 40,
minlength: 4,
required: true
},
password: {
type: String,
required: true,
minlength: 8
}
favorites: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Recipe'
}]
}, { timestamps: true });
And now assuming I have this doc of Users,
How can I count the total number the Recipe ID (5daef9a2761d4b1668214dbc) present in each User doc's favorites array?
[{
username: 'john123',
email: 'john#test.com',
favorites: ['5daef9a2761d4b1668214dbc']
}, {
username: 'jane75',
email: 'jane#test.com',
favorites: []
}, {
username: 'johnwick',
email: 'johnwick#test.com',
favorites: ['5daef9a2761d4b1668214dbc']
}]
// Should yield 2
I looked up for answers but I can't find one. I'm new to mongodb and nodejs so please bear with me. Some answers that I saw are related to Aggregation.
So far I have tried this code. But it just return the number of User documents.
const User = require('./User') // the User model
RecipeSchema.methods.updateFavoriteCount = function() {
return User.count({
favorites: {
$in: [this._id]
}
}).then((count) => {
this.favoritesCount = count;
return this.save();
});
};
You can do it with the help of aggregation and with $size. For more detail, refer to this document.
Your query
db.collection.aggregate([
{
$project: {
username: 1,
email: 1,
totalFavritesCount: {
$cond: {
if: {
$isArray: "$favorites"
},
then: {
$size: "$favorites"
},
else: "NA"
}
}
}
}
])
Result
[
{
"_id": ObjectId("5a934e000102030405000000"),
"email": "john#test.com",
"totalFavritesCount": 1,
"username": "john123"
},
{
"_id": ObjectId("5a934e000102030405000001"),
"email": "jane#test.com",
"totalFavritesCount": 0,
"username": "jane75"
},
{
"_id": ObjectId("5a934e000102030405000002"),
"email": "johnwick#test.com",
"totalFavritesCount": 1,
"username": "johnwick"
}
]
You can also check out the running code in this link.

How to use properly nested mongoose model and schema

This is my schema. I am new to mongoose but trying the policy why to send extra info when not required. I have tried to do a subDocument for comments and likes.
var post = new Schema({
postid: {type: Number, required: true, unique: true},
title: {type: String, required: [true, 'Title cannot be blank']},
startdate: {type: Date, required: true, default: Date.now},
enddate: {type: Date, required: true, default: new Date(+new Date() + 15 * 24 * 60 * 60 * 1000)},
comments: [
{
id: {type: Number, required: true},
message: {type: String, required: true},
userid: {type: String, required: true, unique: true},
updated_at: {type: Date, required: true, default: Date.now, select: false},
likes: [
{
userid: {type: String, required: true, unique: true},
updated_at: {type: Date, required: true, default: Date.now},
}
],
}
],
}, {
timestamps: {
createdAt: 'created_at',
updatedAt: 'updated_at'
}
});
post.index({postid: 1});
I am doing some dirty tricks to get the data in rest api by using lean().
// post [GET]
[
{ postid: 1, title: "dfdsfadsf", startdate: "dafdsfadsf", enddate: "dsafdsfads", commentscount: 6},
{ postid: 2, title: "ffdsfadsf", startdate: "dafdsfadsf", enddate: "dsafdsfads", commentscount: 5},
]
// post/:id [GET]
{
postid: 1,
title: "dfdsfadsf",
startdate: "dafdsfadsf",
enddate: "dsafdsfads",
comments: [{
{id: 1, message: "ddsfsfadsfa", likescount: 6},
{id: 2, message: "dsfafdrsdsfa", likescount: 3},
{id: 3, message: "dsfaefdsdsfa", likescount: 4},
{id: 4, message: "dfsfdsfadsfa", likescount: 5},
{id: 5, message: "fdsfdsfadsfa", likescount: 7},
{id: 6, message: "dsfadwsfadsf", likescount: 0}
}]
}
// post/:id/comments/:commentid/likes [GET]
{
id: "1",
message: "fadsfads",
likes: [
{ userid: 1, updated_at: "some date" },
{ userid: 2, updated_at: "some date" },
{ userid: 3, updated_at: "some date" },
{ userid: 4, updated_at: "some date" },
{ userid: 5, updated_at: "some date" },
{ userid: 6, updated_at: "some date" }
]
}
Using mysql it was pretty easy to use an ORM and do all these with one single query. Now in mongoose I am doing this in a bad way, like
for the first route, I am doing
Posts.find({}).select({
postid: true,
title: true,
startdate: true,
enddate: true,
comments: true
}).lean().exec(function(err, doc){
if (doc) {
if(doc.comments.length > 0) {
doc.commentcount = doc.comments.length;
delete doc.comments;
}
}
});
Same way I am doing for other two routes. I feel there might be a proper way to do all these using mongoose model. I have tried using aggregate & populate. But not my piece of cake.
If anyone can guide how to use the ORM and fetch data properly for one, I'll be glad and can do the rest.
You can only add likescount: {type: Number} in comments field and increment this field when .push new object to likes field.

Mongoose creates incomplete documents

So, I am trying to seed the database with some sample data that I have in JSON format. Here is the function:
request(options, (err, res, body) => {
if (!err && body) {
var classId;
body.forEach((element, i) => {
Student.create(element, (err, success) => {
if (err) {
console.log("This is a error", err)
} else if (i % 4 === 0) {
console.log(`This is the division for ${i}`, i % 4)
let testClass = new Class();
console.log(testClass)
testClass.name = `Class ${i}`;
testClass.students.push(success._id);
testClass.save((err, successClass) => {
console.log("This is the class created", successClass)
classId = successClass._id;
console.log("This is a the class id", classId)
User.findOne({ email: 'admin#example.com' }, (err, foundUser) => {
foundUser.classId.push(successClass._id);
})
})
} else {
console.log(classId)
Class.findById(classId, (err, foundClass) => {
foundClass.students.push(success._id);
foundClass.save();
})
}
})
})
}
});
I am facing two different problems with this code, 1. Mongoose creates a few incomplete documents. 2. ClassId variable can't store the value.
For second problem, I'll ask a different question.
The logic here is that I have a sample of 20 students, and I want to create 5 groups with 4 students each.
Here is what I get in my console
This is the division for 0 0
{ _id: 595b028dc7000c18b71d14b5,
activeStaus: true,
students: [],
dateCreated: 2017-07-04T02:50:47.296Z,
teachers: [] }
undefined
undefined
This is the division for 4 0
{ _id: 595b028dc7000c18b71d14b6,
activeStaus: true,
students: [],
dateCreated: 2017-07-04T02:50:47.296Z,
teachers: [] }
This is the division for 8 0
{ _id: 595b028dc7000c18b71d14b7,
activeStaus: true,
students: [],
dateCreated: 2017-07-04T02:50:47.296Z,
teachers: [] }
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
This is the division for 16 0
{ _id: 595b028dc7000c18b71d14b8,
activeStaus: true,
students: [],
dateCreated: 2017-07-04T02:50:47.296Z,
teachers: [] }
This is the division for 12 0
{ _id: 595b028dc7000c18b71d14b9,
activeStaus: true,
students: [],
dateCreated: 2017-07-04T02:50:47.296Z,
teachers: [] }
undefined
undefined
undefined
This is the class created { __v: 0,
name: 'Class 4',
_id: 595b028dc7000c18b71d14b6,
activeStaus: true,
students: [ 595b028dc7000c18b71d14a5 ],
dateCreated: 2017-07-04T02:50:47.296Z,
teachers: [] }
This is a the class id 595b028dc7000c18b71d14b6
This is the class created { __v: 0,
name: 'Class 8',
_id: 595b028dc7000c18b71d14b7,
activeStaus: true,
students: [ 595b028dc7000c18b71d14a9 ],
dateCreated: 2017-07-04T02:50:47.296Z,
teachers: [] }
This is a the class id 595b028dc7000c18b71d14b7
This is the class created { __v: 0,
name: 'Class 0',
_id: 595b028dc7000c18b71d14b5,
activeStaus: true,
students: [ 595b028dc7000c18b71d14a1 ],
dateCreated: 2017-07-04T02:50:47.296Z,
teachers: [] }
This is a the class id 595b028dc7000c18b71d14b5
As you can see in the logs that the first few documents don't have the name property and they have empty students array.
I think it has something to do the iteration, because in my head the values of i would be 0,1,2,3,4...19 in that order, even if that's not the case, I still can't understand the incomplete documents.
Edit: Here are the classSchema and studentSchema
Student Schema
var StudentSchema = new Schema({
name: String,
role: String,
added: { type: Boolean, default: false },
email: {
type: String,
lowercase: true
},
password: String,
provider: String,
pin: String,
school: String,
salt: String,
schoolId: mongoose.Schema.Types.ObjectId,
classId: mongoose.Schema.Types.ObjectId,
teacherId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
className: String,
activeStaus:{type:Boolean,default:true},
grade: String,
grade_id: Number,
teacheName: String,
teacherNumber: String,
teacherEmail: String,
courseName: String,
courseNumber: String,
courseId: Number,
period: Number,
gender: String,
number: Number,
realisticInterests: Number,
investigativeInterests: Number,
artisticInterests: Number,
socialInterests: Number,
entrepreneurialInterests: Number,
conventionalInterests: Number,
careerDecidedness: Number,
neuroticism: Number,
extraversion: Number,
opennessToExperience: Number,
conscientiousness: Number,
agreeableness: Number,
activeLearner: Number,
reflectiveLearner: Number,
theoreticalLearner: Number,
progmaticLearner: Number,
socialDesirability: Number
});
Class Schema
var classSchema = new Schema({
schoolId: mongoose.Schema.Types.ObjectId,
teachers:Array,
dateCreated:{type:Date,default:Date.now()},
name : String,
students:[{type:mongoose.Schema.Types.ObjectId,ref:'User'}],
activeStaus:{type:Boolean,default:true}
});
Sample Data
I can't post the complete data since it would overpopulate this thread, and I have checked the data thoroughly, it isn't any required property. Here is a sample
{
"Sr. No.": 1,
"school_name": "Franklin High School",
"school_number": 1001,
"school_id": "",
"grade": 11,
"grade_id": "",
"teacher_name": "Merideth Merrill",
"teacher_number": 539224,
"teacher_id": "",
"teacher_email": "",
"course_name": "Physics 1",
"course_number": 101,
"course_id": "",
"period": 1,
"student_name": "Agnes Walters",
"student_gender": "",
"student_number": "",
"student_id": 1000,
"student_pin": "",
"student_email": "",
"realistic_interests": 1.55,
"investigative_interests": 4.55,
"artistic_interests": 4.92,
"social_interests": 4.96,
"entrepreneurial_interests": 1.98,
"conventional_interests": 4.5,
"career_decidedness": 4.66,
"neuroticism": 2.49,
"extraversion": 1.98,
"openness_to_experience": 1.92,
"conscientiousness": 2.14,
"agreeableness": 0.71,
"active_learner": 4.86,
"reflective_learner": 4.08,
"theoretical_learner": 4.99,
"progmatic_learner": 3.18,
"social_desirability": 0.92
},

How to save child Schema in mongodb using mongoose

Following is my order object that I am trying to save -
{
shipper:
{ firstName: 'Test ShipName',
address1: '10 Florida Ave',
phone1: '800-123-4567' },
consignee:
{ firstName: 'AAA Manufacturing',
address1: '100 Main Street' },
items:
[
{ length1: 45, weight1: 12, height1: 45, width1: 34 },
{ length2: 42, weight2: 34, height2: 90, width2: 54 }
]
}
On doing this -
Order(order).save(function(err, result){
if(err)
throw err;
console.log(result);
});
shipper, consignee are saving appropriate values but in database(mongodb), items are not saving properly -
"items" : [
{
"_id" : ObjectId("54e36e18c59700b513a5309d")
},
{
"_id" : ObjectId("54e36e18c59700b513a5309c")
}
],
Following is my oderSchema -
var orderSchema = mongoose.Schema ({
shipper: {type: addressSchema, 'Default':''}},
consignee: {type: addressSchema, 'Default':''} },
items: {type: [itemSchema], 'Default':''} },
});
Following is my itemSchema -
var itemSchema = mongoose.Schema({
length: {type: Number, required: false },
width: {type: Number, required: false },
height: {type: Number, required: false },
weight: {type: Number, required: false },
});
Let me know what I am doing wrong in saving the item info.
In your itemSchema, the properties are "length", "width" etc, however properties of the data that you're saving contains numbers at the end "length1", "length2", etc. You need to remove those numbers.

Resources