Find by id but update subschema - node.js

So I've created the following model with a subschema (allocationAndLocationSchema). Each MovementSchema will have many embedded allocationAndLocationSchemas in it. I need to update individual allocationAndLocationSchemas and save them to the model.
I've tried doing a forEach on the subschema but updating that doesn't seem to work. Is there a simple solution to search for the model by id (createdByUserID) and the subschema by userID then update it's latitude and longitude?
Model and subschema:
var allocationAndLocationSchema = new Schema({
roleID: String,
roleTitle: String,
userID: String,
latitude: String,
longitude: String,
lastUpdated: Date
});
var MovementSchema = new Schema({
dateCreated: Date,
createdByUserID: String,
dateEdited: Date,
allocationAndLocation: [allocationAndLocationSchema]
});

Its just raw so, take idea from it.
MovementSchema.findByIdAndUpdate({createdByUserID:req.body.createdByUserID,'allocationAndLocation.userID': req.body.userID},{$set:{allocationAndLocation.$.longitude:req.body.longitude ,allocationAndLocation.$.latitude : req.body.latitude},function(err,res){
//call back function
}

Related

How to define an object in NodeJS schema?

I currently have a schema like this:
const postSchema = mongoose.Schema({
title: String,
message: String,
name: String,
creator: String,
tags: [String],
selectedFile: String,
likes: { type: [String], default: [] },
createdAt: {
type: Date,
default: new Date(),
},
})
One of the problem that I anticipate is that as the number of users grow, searching the likes array will become inefficient. Is there a way to store the likes array instead as an Object (key would be userId and value could be true) so that finding someone in the Object would become more efficient.
I am also open to hearing any other ideas that you might have.
Thanks!
I want to suggest populate() for this. From that, you can manage a large no. of user information without a problem. You can create a new schema as likes and add the id of the likes document as an id with the populate. Check the below example.
const likeSchema = mongoose.Schema({
type: [String],
default: [] },
});
const Like = mongoose.model("Like", likeSchema);
Then create the postschema like below.
const postSchema = mongoose.Schema({
title: String,
message: String,
name: String,
creator: String,
tags: [String],
selectedFile: String,
likes: {
type: mongoose.Schema.Types.String,
ref: 'Like',
},
createdAt: {
type: Date,
default: new Date(),
},
})
const Post = mongoose.model("Post", postSchema);
You can easily get all the data inside a likes document by populating when running a query like below.
const posts = await Post.findById({creator_id}).populate("likes");
//Below code will print the data of the first element of the type array of relevant likes document.
console.log(posts.likes.type[0]);
Check the populate and population sections of the mongoose documentation to learn more.

Mongoose Schema how to change date.now whenever DB is updated

How Can we change the value of updated_at whenever Data of DB is updated
Consider this to be my Mongoose Schema,
const mongoose = require('mongoose')
const locationDataSchema = new mongoose.Schema({
locationName: String,
location: [{
lat: Number,
lng: Number
}],
news: [ {
author: String, //or number
title: String,
description: String,
url: String,
urlToImage: String
}],
updated_at: {
type: Date,
default: Date.now
}
})
From my Vaguely reading of Mongoose Docs, I did something like this
locationDataSchema.post('save', (next) => {
console.log("here")
this.locationName = this.locationName.toLowerCase();
this.updated_at = Date.now()
})
But this isn't being called whenever I create/update something in my mongoose Schema
Question: Can someone help me in figuring out how can I change
updated_at = Date.now()
Whenever user updates data in DB (similarly changing location Name to Lowercase)
The current version of Mongoose (v4.x) has time stamping as a built-in option to a schema:
var mySchema = new mongoose.Schema( {name: String}, {timestamps: true} );
This option adds createdAt and updatedAt properties that are timestamped with a Date, and which does all the work for you.
For more please look at
https://mongoosejs.com/docs/guide.html#timestamps

Adding field to schema using mongoose in node js

I am trying to write a schema that takes the parameters required by an activity. I am want to add a field 'activityParameters' that will be case specific depending on the activityType. Suppose if the activityType is email then the activityParameters should store details like'to:String, from:String, subject: String, body: String' and if the activity is "export" then it should store parameters like 'path:String' . Different types of activity will have different parameters. Please help me how to do this.
var activity_type = {
values: 'email export'.split(' '),
message: 'validation failed for path `{PATH}` with value `{VALUE}`'
};
var activitySchema = new Schema({
activityName: String,
activityDescription: String,
executionTime: {type: Date , default: null},
activityStartTime: {type: Date , default: null},
activityCompletionTime: {type: Date , default: null},
activityType: {type:String, enum: activity_type},
//activityParameters: ,
appName : String,
activityRetryCount: {type:Number,default:0},
createdOn: {type:Date , default:Date.now},
deletedOn: {type: Date , default: null},
updatedOn: {type: Date , default: null}
});
There's really no good answer for doing this with mongoose and maintaining a strongly typed schema.
You can specify all the fields for each type on the schema and then use them depending on type (export vs message).
var activitySchema = new Schema({
...
activityParameters: {
to:String,
from:String,
path:String
}});
You might consider having a key per subtype to be an improvement:
var activitySchema = new Schema({
...
emailActivityParameters:{
to:String,
from:String,
},
exportActivityParameters:{
path:String,
}
});
It would be pretty easy to access each "subdocument" depending on the activity type.
Finally, you can have a key called activityParameters and have that be freeform json:
var activitySchema = new Schema({
...
activityParameters: {}
});
In this case you can preserve your schema integrity using custom validators.
If these approaches don't appeal then maybe mongoose isn't the right tool you. You could use a lower level mongo driver and then something like Typescript or json schema to validate your models before you save them to mongoose. Check out this, for example: https://github.com/litixsoft/lx-valid.

Error while defining mongoose schemas

I am new to mongo and mongoose. I am trying to create 3 collections Users, Articles and Comments. I want the users documents should contain articles that users have saved. The articles object should have users and comments as embedded objects and comments should have embedded user objects.
I want this to be done using the ids of the individual objects so that I can reduce the loading time, but could not find a suitable way to do so using mongoose. Please suggest how should I proceed with the Schema implementation.
var UserSchema = new mongoose.Schema({
name: String,
email: String,
profilePicture: String,
password: String,
readingList: [articleSchema]
});
var commentsSchema = new mongoose.Schema({
content: String,
votes:{
up:[UserSchema],
down:[UserSchema]
},
comments:[commentsSchema],
timestamp:Date.now
});
var articleSchema = new mongoose.Schema({
title: String,
content: String,
image: String,
votes:{
up: [UserSchema],
down: [UserSchema]
},
comments:[commentsSchema],
timestamp: Date.now
});
What you have is failing because articleSchema isn't defined when you're using it in the UserSchema. Unfortunately, you can reverse the order of defining the schema because they're dependent on each other.
I haven't actually tried this, but based on some quick googling there is a way to create the Schema first and then add the properties.
var UserSchema = new mongoose.Schema();
var CommentsSchema = new mongoose.Schema();
var ArticleSchema = new mongoose.Schema();
UserSchema.add({
name: String,
email: String,
profilePicture: String,
password: String,
readingList: [ArticleSchema]
});
CommentsSchema.add({
content: String,
votes:{
up:[UserSchema],
down:[UserSchema]
},
comments:[CommentsSchema],
timestamp:Date.now
});
ArticleSchema.add({
title: String,
content: String,
image: String,
votes:{
up: [UserSchema],
down: [UserSchema]
},
comments:[CommentsSchema],
timestamp: Date.now
});

Can't update Mongoose subdocument property

Using the following line of code I can update a given Transaction (document), but when I try to update properties of its subdocument, the given value is not persisted.
Transaction.findById('55cf89abe148323e5368dcd5').populate('cryptocurrencies')
.then(function(transaction){
transaction.status = 'completed'; // this updates the transaction status correctly
transaction['cryptocurrencies'][0].status = 'ordered'; // this update is not persisted
return transaction.save()
.then(function(transaction){
console.log(transaction['cryptocurrencies'][0].status); // this shows the status as updated, but it's not persisted
})
})
I've also used the line transaction['cryptocurrencies'][0].markModified('status'); after I update the property to no avail. Can't find anything in the docs: What am I missing?
Update: I've tested this further and found that I have to use the .save() method on both the document and its subdocument. Is there any I can run a method that will save the document with its subdocument properties changed, or do I have to run two operations to save one document each time?
Update:
Here is my model code:
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var TransactionSchema = new Schema({
userId: { type: String, required: true },
status: { type: String, enum: ['unpaid', 'failed', 'paid', 'ordered', 'received', 'withdrawn', 'completed'] },
invoice: String,
saltStatus: String,
saltTransactionId : Number,
saltBank: String,
saltConfirmation: String,
saltAmount : Number,
saltDate : String,
saltResponseCode: String,
cryptocurrencies: [{ type: mongoose.Schema.Types.ObjectId, ref: 'CryptoCurrency' }]
});
var CryptoCurrencySchema = new Schema({
currencyName: String,
price: Number,
amount: Number,
total : Number,
walletAddress: String,
dollarsPaid : Number,
exchangeTransactionId: Number,
coinTransactionId : String,
status: { type: String, enum: ['ordered', 'received', 'withdrawn'] }
});
module.exports.Transaction = mongoose.model('Transaction', TransactionSchema);
module.exports.CryptoCurrency = mongoose.model('CryptoCurrency', CryptoCurrencySchema);
From your code example it seems that you are saving the sub-documents as references which means that once you update the sub-document, you only need to call .save() for it and not the parent document as well.
If you are saving your documents as sub-schemas, once updating the sub-document you can call .save() only for the parent document and it will persist the child document as well.
From the docs:
Sub-documents enjoy all the same features as normal documents. The
only difference is that they are not saved individually, they are
saved whenever their top-level parent document is saved.
http://mongoosejs.com/docs/subdocs.html

Resources