Mongodb update push Array of Objects - node.js

I am unable to solve this issue (and looking to avoid loop update one by one), please hep me out here.
I have a fambio document (which has its own FamilyModel) which gets created after user gives his below information:
{
name: 'john',
lname: 'doe',
}
Now, after above information gets saved, user provides more information about the family after some processing in backend:
let familyArr = [
{ _id: 1234, name: 'Jenny', lname: 'doe', relation: 'mother' },
{ _id: 2345, name: 'Jawn', lname: 'doe', relation: 'father' },
{ _id: 3456, name: 'Jane', lname: 'doe', relation: 'sister' },
{ _id: 4567, name: 'Daisy', lname: 'wick', relation: 'pupper' }
]
Altogether, FamilyModel schema looks like:
const FamilyModel = mongoose.Schema({
name: {type: String, required: true},
lname: {type: String, required: true},
family: [relationshipSchema]
}, {
timestamp: true
});
const relationshipSchema = mongoose.Schema({
name: {type: String, required: true},
lname: {type: String, required: true},
relation: {type: String, required: true}
}, {
required: false,
timestamp: true
});
Now, John has an array of objects of family (filed type Array) and trying to insert that Array of Object like this:
What I tried multiple options:
db.fambio.updateOne({_id: 1111}, { $set: { family: familyArr }})
db.fambio.findOneAndUpdate({_id: 1111}, { $push: { family: familyArr }});
db.fambio.update({_id: 1111}, $addToSet: { 'family': familyArr}});
Nothing is working with respect to insert the constructed Object directly to the field. When I insert one at a time, it gets updated.
How am I supposed to write the query to update/append an Array of Objects in to a field of Array Type having its own Schema maintained.

Okay, I've solved it. How I solved it:
Initially, I saved the document and did some processing on the info as per my requirements post which I wanted to insert Array of Elements in to an Array key field where I was running in to the issue of nothing getting inserted. What I was missing was $each and this is how I did it:
db.getCollection('fambio').update({
_id: johnsuserid
}, {
$push: {
'family': {
$each:[
{ _id: 1234, name: 'Jenny', lname: 'doe', relation: 'mother' },
{ _id: 2345, name: 'Jawn', lname: 'doe', relation: 'father' },
{ _id: 3456, name: 'Jane', lname: 'doe', relation: 'sister' },
{ _id: 4567, name: 'Daisy', lname: 'wick', relation: 'pupper' }
]
}
}
});
Thank you everyone!! Hope this helps someone who may face this problem in future.

Related

How to add value inside an array of array in mongoose by value find by ID?

I want to add the data inside the order products_id array
I tried to push the array by find it by user id and then add push it inside the products_id but i won't able to add the data.
User.findById(user_id,(err,user)=>{
if(err) throw err;
const lastOrderId = user.order.slice(-1)[0]._id
//console.log(cb.order.slice(-1)[0]._id);
User.update({'order[0]._id': lastOrderId}, {$push: {'order.0.$.products_id': 123}},{safe:true,upsert:true})
/*User.findOneAndUpdate({'_id' : user_id, 'order._id': lastOrderId}
,{$push: [{'order[0].products_id': [123123]}]},{safe:true,upsert:true})*/
})
My User Schema
const userSchema = mongoose.Schema({
_id: mongoose.Types.ObjectId,
user_name: {type:String,require: true},
email: {type:String, require: true},
password: {type:String,require:true},
full_name: {type:String},
order: [{
_id: mongoose.Types.ObjectId,
products_id: [],
date: {
type: Date,
default: Date.now
}
}]
})
After updating i want
const userSchema = mongoose.Schema({
_id: mongoose.Types.ObjectId,
user_name: {type:String,require: true},
email: {type:String, require: true},
password: {type:String,require:true},
full_name: {type:String},
order: [{
_id: mongoose.Types.ObjectId,
products_id: [5d5d7a7ea0c4aaf6212993ec, 5d627a962a5c637e7a0d5d1c, 5d627a49fa24ba7d15451afb],
date: {
type: Date,
default: Date.now
}
}]
})
You can use arrayFilter for this.You can do it like this.
User.update({user_id},{$set: { 'order.$[ord]': lastOrderId },
$push: {'order.$[ord].products.$[prd]':123}
}, {
arrayFilters: [{'_id': user_id}]
})

How to name a foreign key different from db name in mongoose

Is there a way in mongoose + Node.js/Express to define the relation between the foreign key field and what I refer to that field in the model is? My issue is that I have a mongo database where my foreign keys are all formatted like 'exampleId' instead of 'example'. I could just call out 'exampleId' directly but then it leads to weird things like when I populate 'exampleId' instead of 'example' (which is confusing because once populated, it is now the 'example' itself instead of its id).
Here is how I do it now and it works with my graphQL server, but only if my field in the database is 'course' while my database's field is 'courseId'
const CourseSchema = new Schema({
_id: { type: String },
sections: [{
type: Schema.Types.String,
ref: 'Section'
}],
});
const SectionType = new GraphQLObjectType({
name: 'SectionType',
fields: () => ({
id: { type: GraphQLID },
courseId: {
type: require('./course_type'),
resolve(parentValue) {
return Section.findById(parentValue)
.populate('course')
.then(section => section.course);
}
},
}),
});
I figured it out! With the newest version of mongoose, you actually can use virtual fields to accomplish what I wanted to do and this technique allows for flexibility in laying out your schema. Say that my MongoDB collections look like the following:
Courses { _id, sectionIds }
Lectures { _id, courseId }
I can use the following schema in mongoose and it will allow me to refer to course.lectures or lecture.course instead of the usual course.lectureIds or section.courseId:
const CourseSchema = new Schema({
_id: { type: String },
});
CourseSchema.virtual('sections', {
type: Schema.Types.String,
ref: 'Section',
localField: 'sectionIds',
foreignField: '_id',
justOne: false,
});
CourseSchema.statics.findSections = function(id) {
return this.findById(id)
.populate('sections')
.then(course => course.sections);
}
const SectionSchema = new Schema({
_id: { type: String },
});
SectionSchema.virtual('course', {
type: Schema.Types.String,
ref: 'Course',
localField: 'courseId',
foreignField: '_id',
justOne: true,
});
Actually MongoDB isn't a relational database. You can alter the field and its name whatever you like. Ex I Have an Owner(Meteor.users) table and Patient Table with this column
ownerid : {type: String, min: 1},
firstname: {type: String, min: 1},
lastname: {type: String, min: 1},
middlename: {type: String, min: 1, optional: true},
createdbyid: { type: String },
createdbyname: { type: String },
createdat: { type: Date, defaultValue: new Date() },
updatedbyid: { type: String, optional: true },
updatedbyname : { type: String, optional: true },
updatedat: { type: Date, defaultValue: new Date() },
I can easily stamp the value of my {Meteor.Users()._id} to ownerid of my designated patient by just processing them at meteor.methods. You don't have to worry about foreign keys mongo doesn't do relational databases you can customize your database whatever you like. I Hope this helps ;)
Mongoose Documentation posits that _id has to be used in refs and that[i]t is important to match the type of _id to the type of ref. , e.g.:
var personSchema = Schema({
_id : Number, //it is `Number`
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }] // use `Number` to match
});
I also wonder if by 'database' you mean 'collection'.

NodeJS + MongoDB Sort Query

I am trying to sort alphabetically with node and mongodb. This is my current condition, however it does not work:
$addToSet: {
friends: {
$each: [{
_id: req.body.globalUserId.toString(),
username: req.body.globalUserName,
language: req.body.globalUserLanguage,
profilePicture: req.body.globalUserProfilePicture
}],
$sort: {username: 1}
}
}
Here is an example document:
As you can see under the friends array, it goes 'r1' and then 'a' second. Since I would like this array to be sorted alphabetically, the 'a' would go first. How would I do this? Thanks so much!
Here is my Schema for this particular model:
username: String,
email: String,
password: String,
language: { type: String, default: "English" },
profilePicture: { type: String, default: "/images/talk/blank-profile-picture.png" },
pendingFriends: [this],
friends: [this]
Sets are unordered and for the same reason $sort is not supported.
$push will maintain the order.
$push: {
friends: {
$each: [{
_id: req.body.globalUserId.toString(),
username: req.body.globalUserName,
language: req.body.globalUserLanguage,
profilePicture: req.body.globalUserProfilePicture
}],
$sort: {username: 1}
}
}

How I can select only one field from every object in array using Mongoose?

I have schema:
{
name: String,
surname: String,
note: String,
someField: String,
secondSomeField: String
blackList: [{
userId: mongoose.Types.ObjectId,
reason: String
}]
}
I need select document with all fields, but in blackList field I need select only userId. Example what I want:
{
name: "John",
surname: "Doe",
note: "bwrewer",
someField: "saddsa",
secondSomeField: "sadsd",
blackList: [58176fb7ff8d6518baf0c931, 58176fb7ff8d6518baf0c932, 58176fb7ff8d6518baf0c933, 58176fb7ff8d6518baf0c934]
}
How I can do this? When I do
Schema.find({_id: myCustomUserId}, function(err, user) {
//{blackList: [{userId: value}, {userId: value}]}
//but i need
//{blackList: [value, value, value]}
})
If you want to hide the field by default:
{
name: String,
surname: String,
note: String,
someField: String,
secondSomeField: String
blackList: [{
userId: mongoose.Types.ObjectId,
reason: {type:String, select:false}
}]
}
If you simply want to exclude in that query:
Schema
.find({_id: myCustomUserId})
.select("-blackList.reason")
.exec(function (err, user) {
//your filtered results
})
Not tested but they should work both.
Schema.aggregate( {$match: {_id: mongoose.Types.ObjectId(myCustomId)} }, {$project: {blackList: "$blackList.userId", name: true, surname: true, someField: true}} ).exec(fn)

How to better structure mongoose schemas with relationships

At the moment i have 4 models. User, profile, interests and tokens. Between user and profile there is a one to one relationship. Between User and tokens there is a one to many relationship. Between profile and interests there is also a one to many relationships, interests will be pre defined with the ability for an admin to add more later.
User
var UserSchema = new Schema({
email: {
type: String,
lowercase: true,
unique: true,
required: true
},
phone: [{countrycode: String}, {number: String}],
tokens: [{type: Schema.Types.ObjectId, ref: 'Token'}],
profile: {
type: Schema.Types.ObjectId, ref: 'Profile'
},
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
Profile
var ProfileSchema = new Schema({
username: {
type: String,
unique: true,
},
firstname: {
type: String
},
lastname: {
type: String
},
gender: {
type: String
},
dob: {
type: Date
},
country: {
type: String
},
city: {
type: String
},
avatar: {
type: String
},
about: {
type: String
},
interests: [{
type: Schema.Types.ObjectId,
ref: 'Interest'
}],
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
Token
var TokenSchema = new Schema({
name: {
type: String,
},
value: {
type: String,
},
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
Interests
var InterestSchema = new Schema({
name: {
type: String,
unique: true,
},
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
Have i set up these schemeas/relationships properly? Now if i wanted to give roles to a user would i create a new role schema?
thanks.
I think you need Relational database if you want to make relation in NoSQL db
You can't add relations in NoSQL. Only thing you can is to use schema as type of field in another schema, like
var Comments = new Schema({
title: String,
body: String,
date: Date
});
var BlogPost = new Schema({
author: ObjectId,
title: String,
body: String,
date: Date,
comments: [Comments],
meta: {
votes : Number,
favs : Number
}
});
mongoose.model('BlogPost', BlogPost);
Embedded Documents

Resources