Nested MongoDB document issue (Mongoose and Node Js) - node.js

I am facing some issues while inserting data into nested documents structure of mongoDb.
Following is the Mongoose Model:
const funnel = new mongoose.Schema({
funnelName:{
type:String,
unique:true
},
group: String,
category: String,
funnelStep: {
stepType: String,
stepName: String,
stepPath: String,
isTracking: Boolean,
viewsStorage: []
} })
Below is the push I am sending to Db:
router.post('/createFunnel',async (req,res)=>{
if(!req.body.funnelName || !req.body.group || !req.body.category)
{return res.status(422).json({error:"Please add all the fields."})}
try{
const funnelSteps = []
funnelSteps.push({
stepType: req.body.stepType,
stepName: req.body.stepName,
stepPath: req.body.stepPath,
isTracking: req.body.isTracking,
viewsStorage: req.body.viewsStorage
})
const funnels = new Funnel({
funnelName : req.body.funnelName,
group : req.body.group,
category : req.body.category,
funnelStep : funnelSteps
})
await funnels.save(function(err){
if(err){
return res.status(422).send({error: err.message})
}
return res.json(funnels)
})
} catch(err){
return res.status(422).send({error: err.message})
} })
Below is the data structure I am sending through postman:
{
"funnelName":"Name-Funnel",
"group":"AVC",
"category":"XYZ",
"funnelStep":[
{
"stepType":"Advert",
"stepName":"Angle",
"stepPath":"google.com",
"isTracking":1,
"viewsStorage":[0,0]
},
{
"stepType":"Optin",
"stepName":"Ver 1",
"stepPath":"fb.com",
"isTracking":1,
"viewsStorage":[1,0]
},
{
"stepType":"Check",
"stepName":"rev-cat",
"stepPath":"google.com",
"isTracking":0,
"viewsStorage":[2,0]
}
] }
Below is the output I am getting in response:
{
"funnelStep": {
"viewsStorage": []
},
"_id": "5ec0ff78a6dfab18f4210e96",
"funnelName": "Testing The Latest Method4",
"group": "AVC",
"category": "XYZ",
"__v": 0
}
How can I fix this issue as my data is not getting inserted properly?
And apart from this, in the viewsStorage array, how to store date and a number which will increment after a certain operations and will get saved in the array according to the dates?

I think there is an issue in the funnelSteps array creation part. You are trying to get data directly from req.body instead of req.body.funnelStep
const funnelSteps = []
req.body.funnelStep.forEach(fs => {
funnelSteps.push({
stepType: fs.stepType,
stepName: fs.stepName,
stepPath: fs.stepPath,
isTracking: fs.isTracking,
viewsStorage: fs.viewsStorage
})
})
Schema
const funnel = new mongoose.Schema({
funnelName:{
type:String,
unique:true
},
group: String,
category: String,
funnelStep: [{
stepType: String,
stepName: String,
stepPath: String,
isTracking: Boolean,
viewsStorage: []
}] })

Related

how tf do i delete/$pull a specific data from a double-nested schema in mongodb

so...below is the schema, from where, i want to delete a particular 'Comment' from answer array.
const Schemaa = mongoose.Schema({
questionBody: String, //object_id - 61f59463823446723240ed85(_id)
Comment:[{
commentBody: String,
}],
answer: [{
answerBody: String, //object_id - 61f5946b823446723240edad(answerId)
Comment:[{
commentBody:String, // Object _id- 61f5946e823446723240edc4(commentId)
}]
}]
})
export default mongoose.model("Questions", Schemaa)
really stuck at this for hours now... ( ཀ ʖ̯ ཀ)
You can use the $ and $pull methods
const deleteACom = await Question.updateOne(
{ "answer.$.Comment.$._id": "comment id" },
{ $pull: {
"answer.$.Comment": {
_id: "comment id"
}
}
})

Concurrency problems updating another's collection stats

I'm trying to make a notation system for movies
A user can note a Movie in their List.
Whenever the user clicks on the frontend, the listId, movieId, note are sent to the server to update the note. The note can be set to null, but it does not remove the entry from the list.
But if the user clicks too much times, the movie's totalNote and nbNotes are completely broken. Feels like there is some sort of concurrency problems ?
Is this the correct approach to this problem or am I updating in a wrong way ?
The mongoose schemas related :
// Movie Schema
const movieSchema = new Schema({
// ...
note: { type: Number, default: 0 },
totalNotes: { type: Number, default: 0 },
nbNotes: { type: Number, default: 0 },
})
movieSchema.statics.updateTotalNote = function (movieId, oldNote, newNote) {
if (!oldNote && !newNote) return
const nbNotes = !newNote ? -1 : (!oldNote ? 1 : 0) // If oldNote is null we +1, if newNote is null we -1
return Movie.findOneAndUpdate({ _id: movieId }, { $inc: { nbNotes: nbNotes, totalNotes: (newNote - oldNote) } }, { new: true }).catch(err => console.error("Couldn't update note from movie", err))
}
// List Schema
const movieEntry = new Schema({
_id: false, // movie makes an already unique attribute, which is populated on GET
movie: { type: Schema.Types.ObjectId, ref: 'Movies', required: true },
note: { type: Number, default: null, max: 21 },
})
const listSchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'Users', required: true },
movies: [movieEntry]
})
The server update API (add / Remove movieEntry are similar with $push and $pull instead of $set)
exports.updateEntry = (req, res) => {
const { listId, movieId } = req.params
const movieEntry = { movieId: movieId, note: req.body.note }
List.findOneAndUpdate({ _id: listId, 'movies.movie': movieId }, { $set: { 'movies.$[elem]': movieEntry } }, { arrayFilters: [{ 'elem.movie': movieId }] })
.exec()
.then(list => {
if (!list) return res.sendStatus(404)
const oldNote = list.getMovieEntryById(movieId).note // getMovieEntryById(movieId) = return this.movies.find(movieEntry => movieEntry.movie == movieId)
Movie.updateTotalNote(movieId, oldNote, movieEntry.note)
let newList = list.movies.find(movieEntry => movieEntry.movie == movieId) // Because I needed the oldNote and findOneAndUpdate returns the list prior to modification, I change it to return it
newList.note = movieEntry.note
newList.status = movieEntry.status
newList.completedDate = movieEntry.completedDate
return res.status(200).json(list)
})
.catch(err => {
console.error(err)
return res.sendStatus(400)
})
}
The entries I needed to update were arrays that could grow indefinitely so I had to first change my models and use virtuals and another model for the the list entries.
Doing so made the work easier and I was able to create, update and delete the entries more easily and without any concurrency problems.
This might also not have been a concurrency problem in the first place, but a transaction problem.

how to put mongodb items in variables for discord bot?

This is the model:
Schema = mongoose.Schema;
module.exports = mongoose.model(
"Leveling",
new Schema({
guildID: {
type: String
},
guildName: {
type: String
},
roletoad: {
type: String,
default: "null"
},
roletoremove: {
type: String,
default: "null"
},
rolelevel: {
type: Number,
default: 0
},
})
);
This is the command to get all leveling roles in a specific guild:
if(args[0]==="list"){
const del = await Leveling.find({
guildID: message.guild.id,
},{
_id: 0,
roletoad: 1,
roletoremove: 1,
rolelevel:1
})
return await message.channel.send(del)
}
This is the output:
{
roletoad: '735106092308103278',
roletoremove: '731561814407774248',
rolelevel: 5
}
{
roletoad: '735598034385371167',
roletoremove: '744562691817078905',
rolelevel: 7
}
I want to know how to get each item(roletoad,roletoremove,rolelevel) in a specific variable.
It seems you're getting an array of objects form your db in the del variable, and each object in that array has the properties roletoad, roletoremove and rolelevel, which you want in separate variables.
For each object of your array, you can store these properties in variables by object destructuring. One approach is as follows:
//the data you'll get from the db
const del = [{
roletoad: '735106092308103278',
roletoremove: '731561814407774248',
rolelevel: 5
},
{
roletoad: '735598034385371167',
roletoremove: '744562691817078905',
rolelevel: 7
}]
for(const {
roletoad: yourRoleToAddVar,
roletoremove: yourRoleToRemoveVar,
rolelevel: yourRoleToLevelVar
} of del){
console.log(`Role to add: ${yourRoleToAddVar}`)
console.log(`Role to remove: ${yourRoleToRemoveVar}`)
console.log(`Role Level: ${yourRoleToLevelVar}`)
console.log(`---------------------------`)
//do what you want with these variables here
}
NOTE: This should go without saying but the scope of these variables will only be valid within this loop.

Update with $PUSH is not working in Mongoose + Express + Node

This Code is fetching JSON data from an API service correctly but not updating a nested document in MongoDB, Almost tried everthing
api.squad(matchid, function(datapack) {
var data = JSON.parse(datapack);
for (var i = 0; i < data.squad.length; i++) {
players = data.squad[i].players;
for(var j = 0; j < players.length; j++){
console.log(players[j]); // Working Fine Till here , Data from api showing here in console
var player = { pid: players[j].pid, name: players[j].name };
squadModel.update(
{ leagueId: leagueId },
{$push: {players: player} } // This Update is Not Working
);
}
}
});
The Schema Is As Follows for the code.
// Squad Players -- Sub Schema of Squad
var squadPlayersSchema = mongoose.Schema({
pid:{
type: Number,
required: true
},
name:{
type: String,
required: true
},
type:{
type: String,
},
cost:{
type: Number,
},
country:{
type: String,
},
status : {
type:Boolean,
default:false
}
});
// Squad Schema
var squadSchema = mongoose.Schema({
leagueId:{
type: mongoose.Schema.Types.ObjectId,
ref :'leagueModel',
required: true
},
players : [squadPlayersSchema],
isLaunched : {
type:Boolean,
default:false
}
});
var squads = module.exports = mongoose.model('squads', squadSchema);
Pls help this thing has just refused to work. The update query is just working fine in MongoDB GUI Studio3T Shell
Example Of a demo query run in Studio3T and works fine and updates the document with the code above doesn't.
db.squads.update(
{ "leagueId": ObjectId("5a85900d8b3b30165875ff0d") },
{
"$push": {
"players": { pid: 1234567, name: "Some Name" }
}
}
);
Use $each with $addToSet as follows:
api.squad(leagueId, datapack => {
const data = JSON.parse(datapack);
let updates = []; // array to hold updates promises
data.squad.forEach(squad => { // iterate the data.squad array to get the players list
let promise = squadModel.findOneAndUpdate(
{ leagueId: leagueId },
{ '$addToSet': { 'players': { '$each': squad.players } } },
{ 'upsert': true }
); // update operation as a promise
updates.push(promise);
});
Promise.all(updates).then(console.log).catch(console.error); // resolves when all of the updates promises have resolved
});

Mongodb not casting data correctly

When I post data on database, some data are not stored in my database .
Here's the schema of my model :
var ProjSchema = new Schema({
leadProj: String,
nomProj: String,
descProj: String,
BesProj: Number,
pers: [
{
name: String,
poste: String
}
],
backlog: { fonctionnalite: [String], userStory: [String] }
});
I use Express for Api and this is the route
.post(function(req, res) {
var nouvProj = new NouvProj();
nouvProj.nomProj = req.body.nomProj;
nouvProj.leadProj = req.body.leadProj;
nouvProj.descProj = req.body.descProj;
nouvProj.BesProj = req.body.BesProj;
nouvProj.pers = req.body.pers;
nouvProj.backlog.fonctionnalite = req.body.Fonctionnalite;
nouvProj.backlog.userStory = req.body.UserStory;
console.log(req.body.Fonctionnalite);
console.log(req.body.UserStory);
// save the nouvProj and check for errors
nouvProj.save(function(err) {
if (err) {
res.send(err);
console.log("err");
}
res.json({
message: "nouvProj created!"
});
});
})
the output of console.log()
[ { fonctionnalite: 'oijoij' }, { fonctionnalite: 'oio' } ]
[ { userStory: 'oijoij' }, { userStory: 'poihpohi' } ]
The problem is on backlog item . I'm getting empty data in it when I get elements:
backlog : []
Update : I would precise the difference between pers and backlog
Pers item is a table of {name: String, poste }
backlog is table of table of {fonctionnalite: String} and {UserStory : String}
I don't understand why is that working for pers and not for backlog
It seems that req.body.Fonctionnalite and req.body.UserStory are both array of objects and in your shcema they are declared as array of strings, You need to redefine the ProjSchema to take over this behavior:
var ProjSchema = new Schema({
leadProj: String,
nomProj: String,
descProj: String,
BesProj: Number,
pers: [
{
name: String,
poste: String
}
],
backlog: {
fonctionnalite: [ { fonctionnalite: String } ],
userStory: [ { userStory: String } ],
}
});
Or you can keep ProjSchema as it is and update the front-end code in the way that fonctionnalite and userStory posted as a normal arrays:
fonctionnalite => [ 'oijoij', 'oio' ]
userStory => [ 'oijoij','poihpohi' ]
I think you pass only a string to your functionalite while you defined it as an array, you should push the value into your array instead of assigning a string to it.
nouvProj.backlog.fonctionnalite.push(req.body.Fonctionnalite);
nouvProj.backlog.userStory.push(req.body.UserStory);
If you want to define a flexible or loose object (schema-less), its properties or schema fields are specified at runtime, you can use Schema.Types.Mixed
//schema defintion
var proj = new Proj({
myObject: Schema.Types.Mixed
});
//how use it
var proj = new Proj();
proj.myObject = { any: { fields: ['test'] } }
yourSchema.save()
If you want to define your backlog as an array, I would suggest doing this.
var BackLog = new Schema({
fonctionnalite: [String],
userStory: [String]
};
var ProjSchema = new Schema({
leadProj: String,
nomProj: String,
descProj: String,
BesProj: Number,
pers: [
{
name: String,
poste: String
}
],
backlog: [BackLog]
});
// create a project
var proj = new ProjSchema({
....
});
//you notice functionalite is an array, userStory is also an array
proj.backlog.push({ functionalite: ['test'], userStory: ['sss'] });
proj.save(function (err) {
...
}
More info for Mongoose schema and modeling, can be found here or Heroku's Dev. blog.

Resources