Mongoose create a subobject in a subobject - node.js

I want to create a subdocument in a subobject field, not to update.
My Schema:
var DemandeSchema = new Schema({
titre: {
type: String,
required: true
},
description: {
type: String,
required: true
},
type: {
type: String,
required: true
},
answer: {}
});
My code:
demande.update(
{ name: 'answer' },
{ $push: req.body.answer },
{ upsert: true },
function(error, user) {
if (error) return next(error);
else {
return true;
}
}
)
req.body.answer = {
"id": "57f512f4360d8818a4e5ea3d",
"answer": {
"122547eee99" : {
"review" : "1.3",
"login" : "new"
}
}
}
But this code doesn't create a new field in my DB, it just updates the field answer when I just want to create a new object field in the answer field.
Actual Result:
{
"_id" : ObjectId("57f512f4360d8818a4e5ea3d"),
"titre" : "TEST",
"description" : "ee",
"type" : "ee",
"__v" : 0,
"answer" : {
"122547eee98" : {
"review" : "8.8",
"login" : "x"
}
}
}
Expected Result:
{
"_id" : ObjectId("57f512f4360d8818a4e5ea3d"),
"titre" : "TEST",
"description" : "ee",
"type" : "ee",
"__v" : 0,
"answer" : {
"122547eee98" : {
"review" : "8.8",
"login" : "x"
},
"122547eee99" : {
"review" : "1.3",
"login" : "new"
}
}
}

var DemandeSchema = new Schema({
titre: {
type: String,
required: true
},
description: {
type: String,
required: true
},
type: {
type: String,
required: true
},
answer: []
});
Answer field curly braces would convert to square brackets for pushing all new answers.
Conclusion: It creates an array.

Instead of the $push operator which works on arrays, use the $set operator together with the dot notation to set the subdocument in the embedded answer document.
You would need to preprocess the document to use in your update so that it will have the dot notation. The following mongo shell example demonstrates this:
var obj = {
"id": "57f512f4360d8818a4e5ea3d",
"answer": {
"122547eee99" : {
"review" : "1.3",
"login" : "new"
}
}
},
update = {};
var key = Object.keys(obj.answer)[0]; // get the dynamic key "122547eee99"
update["answer."+key] = obj.answer[key]; // create the update object with dot notation
/*
update = {
"answer.122547eee99": {
"review" : "1.3",
"login" : "new"
}
}
*/
db.demandes.update(
{ "_id" : ObjectId(obj.id)},
{ "$set": update },
{ "upsert": true }
)
Using the same concept as above, you can create the documents to use in your update as follows:
var update = {},
key = Object.keys(req.body.answer.answer)[0]; // get the dynamic key "122547eee99"
// create the update object with dot notation
update["answer."+key] = req.body.answer.answer[key];
demande.update(
{ "_id": req.body.answer.id },
{ $set: update },
{ upsert: true },
function(error, user) {
if (error) return next(error);
else {
return true;
}
}
);

Try this, and in schema answer: [],
demande.findOne( { name: 'answer' }, function(err, result){
result.answer.push({ans:req.body.answer})
var dem = new Demande(result); // Demande is ur mongoose schema model,
dem.save(function(err, result){
console.log(result);
});
})

Related

Remove object from nested array of objects

I got this user schema
const UserSchema = new Schema({
email: {
type: String,
required: true,
unique: true,
},
groups: [
{
groupName: {
type: String,
required: true,
},
groupMembers: [{ type: Schema.Types.ObjectId, ref: "GroupMember" }],
},
],
});
And I want to delete a group from the ‘groups’ array based on given ‘userId’ and ‘groupId’, my attempt (with express and mongoose):
router.delete(
"/:userId/:groupId",
catchAsync(async (req, res) => {
const { userId, groupId } = req.params;
const updatedUser = await User.findByIdAndUpdate(
userId,
{ $pull: { "groups.$._id": groupId } },
{ new: true }
);
res.send({ updatedUser });
})
);
The response of the request: I get an error: “The positional operator did not find the match needed from the query.”
Edit:
After I delete a group I need to remove all the group members in the groupMembers array.
User collection structure example:
{
"_id" : "111",
"email" : "michael#gmail.com",
"username" : "michael098",
"groups" : [
{
"_id" : "222"
"groupName" : "family",
"groupMembers" : [
{
"_id" : "333"
"name" : "Liam"
},
{
"_id" : "444"
"name" : "Noah"
}
]
},
{
"_id" : "555"
"groupName" : "friends",
"groupMembers" : [
{
"_id" : "666"
"name" : "Oliver"
}
]
}
]
}
Inside every group there is group members and I have a collection for the group members that I ref in the UserSchema : groupMembers: [{ type: Schema.Types.ObjectId, ref: "GroupMember" }]
GroupMember collection structure example:
{
{
"_id" : "333"
"name" : "Liam"
},
{
"_id" : "444"
"name" : "Noah"
},
{
"_id" : "666"
"name" : "Oliver"
}
}
For example when I get the params of userId="111" and groupId="222" I will delete the whole 'family' group and the whole group members in the groupMembers array (Liam and Noah) from the GroupMember collection.
GroupMember collection after deleting the group with _id="222":
{
{
"_id" : "666"
"name" : "Oliver"
}
}
Assuming an actual doc might look like this (using strings instead of ObjectId to keep the example tighter):
{_id:1, groups: [ { type: "ID1", ref: "XX" }, { type: "ID2", ref: "G1" }, { type: \
"ID3", ref: "G2" } ] }
then this update will remove the subdoc in the groups array where _id = 1 and type = ID2:
db.foo.update({_id:1},
{ $pull: { groups: { type: "ID2" } }}
);

Getting an empty array from mongodb while executing the find query

Thanks in advance, Why I am getting an empty array from the Mongodb even though using the correct schema name?
const Mongoose = require("mongoose");
const studentSchema = Mongoose.Schema({
_id: { type: Number, required: true },
name: { type: String, required: true, max: 30 },
department: { type: String, required: true,max: 30 },
type: { type: String, required: true, min: 7, max: 30 }
});
module.exports = Mongoose.model("StudentInformation", studentSchema);
-----------------------------------------------------------------------
class Service {
static get() {
const data = studentsModel.find({}).then((result) => {
console.log(studentsModel)
return result;
});
return data;
}
}
----------------------------------------------------------------------
```
> db.getCollectionNames();
[ "StudentInformation", "students" ]
> db.StudentInformation.find();
{ "_id" : 1, "name" : "selva", "department" : "CSE", "type" : "regular" }
{ "_id" : 2, "name" : "ashik", "department" : "CSE", "type" : "regular" }
{ "_id" : 3, "name" : "praveen", "department" : "CSE", "type" : "parttime" }
You have a wrong "return" instruction in your get() function:
static get() {
const data = studentsModel.find({}).then((result) => {
console.log(studentsModel)
return result;
});
**return data;**
}
This part is asynchrone
studentsModel.find({}).then((result) => {
Your returning data which is empty / undefined before the execution of the find callback

Mongoose update value in Array of Array in NodeJS

my Test Schema:
var TestSchema = new Schema({
testName: String,
topic: {
topicTitle: String,
topicQuestion: [
{
questionTitle: String,
choice: [
{
name: String
age: Number
}
]
}
]
}
}, { collection: 'test' });
var Test = mongoose.model('test', TestSchema);
I want to update one age ($inc)value which I have the choice id.
I can have test id, topicQuestion id and choice id.
How to write this query in mongoose in NodeJS?
Normally I use the below query to update a value:
Test.findOneAndUpdate({ _id: testId }, { $inc: { ... } }, function (err, response) {
...
});
but it is so difficult to get in array and one more array. Thanks
You can use the $[] positional operator to update nested arrays.
router.put("/tests/:testId/:topicQuestionId/:choiceId", async (req, res) => {
const { testId, topicQuestionId, choiceId } = req.params;
const result = await Test.findByIdAndUpdate(
testId,
{
$inc: {
"topic.topicQuestion.$[i].choice.$[j].age": 1
}
},
{
arrayFilters: [{ "i._id": topicQuestionId }, { "j._id": choiceId }],
new: true
}
);
res.send(result);
});
Let's say we have this existing document:
{
"_id" : ObjectId("5e53e7d9bf65ac4f5cbf2116"),
"testName" : "Test 1",
"topic" : {
"topicTitle" : "Title",
"topicQuestion" : [
{
"_id" : ObjectId("5e53e7d9bf65ac4f5cbf211a"),
"questionTitle" : "Question 1 Title",
"choice" : [
{
"_id" : ObjectId("5e53e7d9bf65ac4f5cbf211c"),
"name" : "A",
"age" : 1
},
{
"_id" : ObjectId("5e53e7d9bf65ac4f5cbf211b"),
"name" : "B",
"age" : 2
}
]
},
{
"_id" : ObjectId("5e53e7d9bf65ac4f5cbf2117"),
"questionTitle" : "Question 2 Title",
"choice" : [
{
"_id" : ObjectId("5e53e7d9bf65ac4f5cbf2119"),
"name" : "C",
"age" : 3
},
{
"_id" : ObjectId("5e53e7d9bf65ac4f5cbf2118"),
"name" : "D",
"age" : 4
}
]
}
]
},
"__v" : 0
}
If we want to increment age value of a given choice, we send a PUT request using endpoint like this http://.../tests/5e53e7d9bf65ac4f5cbf2116/5e53e7d9bf65ac4f5cbf211a/5e53e7d9bf65ac4f5cbf211b where
"testId": "5e53e7d9bf65ac4f5cbf2116"
"topicQuestionId": "5e53e7d9bf65ac4f5cbf211a"
"choiceId": "5e53e7d9bf65ac4f5cbf211b"
You need to inform what choice you want and, on the update section, you need change the way you do increment.
Example:
Test.findOneAndUpdate({ _id: testId, topicQuestion.choice._id: choiceId}, { 'topicQuestion.$.choice': {$inc: { age: <numberToIncrement> }}}, {new: true}, function (err, response) {
...
});

Why do I save the ObjectId('key'), instead of the values in my mongodb? [duplicate]

This question already has answers here:
How to push an array of objects into an array in mongoose with one call?
(4 answers)
Closed 3 years ago.
I'm using Angular 7 with node.js, express and mongoose
I have a problem when adding objects to my mongodb via mongoose, it saves only "_id": ObjectId('randomID') instead of the values i want.
I'm trying to add values to an existing document in my collection with nested arrays.
To be more precise: there are customers with a customer number, customer name and domains.
Domains shall be an array with a domain.
A domain has a name value and two more arrays (called "in" & "out")
both arrays contain a graph array with nodes and links.
nodes have 3 values (id, label, description) and links have also 3 values (source, target, label)
First Problem I have, is that I cant add new domain to my domains array
I don't understand what am I am doing wrong??
Or what is best practice to insert and/or update nested arrays inside nested arrays?
edit: I try to understand, why am I saving only the ObjectId() with no values, linked question doesn't work for me.
here is an Example of what i want in my db:
{
"_id" : ObjectId("5c76a093aac6fa3f140a5672"),
"KdNr" : "10004",
"Kundenname" : "Customer GmbH",
"__v" : 0,
"domains" : [ {
"domain" : "testB.de",
"in" : [ {
"content" : "New Graph B",
"graph" : { ... } } ],
"out" : [ {
"content" : "Another new Graph B",
"graph" : { ... } } ]
}, [ {
"domain" : "testA.de",
"in" : [ {
"content" : "New Graph A",
"graph" : { ... } } ],
"out" : [ {
"content" : "Another new Graph A",
"graph" : { ... } } ]
} ]
}
here is an Example of what i get (not what I want):
{
"_id" : ObjectId("5c76a093aac6fa3f140a5672"),
"KdNr" : "10004",
"Kundenname" : "Customer GmbH",
"__v" : 0,
"domains" : [ {
{ "_id" : ObjectId("5c7f86ad42d63141fc921d04") },
{ "_id" : ObjectId("5c655c828be0b2b295aa126f") }
] }
here is my Schema:
const mongoose = require('mongoose');
const graphSchema = mongoose.Schema({
graph: {
nodes: [{
id: { type: String, required: true, unique: true },
label: { type: String, required: true },
description: { type: String }
}],
links: [{
source: { type: String, required: true },
target: { type: String, required: true },
label: { type: String }
}]
}
});
const domainSchema = mongoose.Schema({
domain: {
name: { type: String, unique: true, required: true },
in: {
content: { type: String },
graphSchema
},
out: {
content: { type: String },
graphSchema
}
}
});
const diagramSchema = mongoose.Schema({
KdNr: { type: String, required: true, index: true, unique: true },
Kundenname: { type: String, required: true },
domains: [{
domainSchema
}]
});
module.exports = mongoose.model('Diagram', diagramSchema);
here is my domains-routes.js:
// core Modules
const express = require('express');
// own modules
const Diagram = require('../models/diagrams');
const router = express.Router();
// add Domain to Diagram
router.put('/:KdNr', (req, res, next) => {
console.log(req.body.domain);
const data = {
domains : [{
domain: req.body.domain,
in: [{
content : "New Graph",
graph : {}
}],
out: [{
content : "New Graph",
graph : {}
}]
}]
}
Diagram.updateOne(
{ KdNr: req.params.KdNr },
{ $push: data }
).then(result => {
if(result) {
console.log('Diagram found in database:');
console.log(result);
res.status(200).json({ message: 'Diagram saved' });
} else {
res.status(404).json({ message: 'Diagram for customer: '
+ req.params.KdNr + 'not found!'})
}
})
})
module.exports = router;
Try this in
Diagram.updateOne
{ $push:{"domains": data }}

Why Mongoose createdAt / updatedAt output a wrong time(only return current time not the time in db)

The Data stored in my db is:
{
"_id" : ObjectId("58da135cfc80bc44f7653fd4"),
"updatedAt" : ISODate("2017-03-28T08:00:59.541Z"),
"createdAt" : ISODate("2017-03-28T07:40:12.742Z"),
"name" : "hello",
"delete" : false,
"enabledPlugins" : [
ObjectId("58c24f65b363502f907738f9")
],
"__v" : 0
}
My Schema Like:
const mongoose = require('./db');
const { Schema } = mongoose;
const templateSchema = new Schema({
name: { type: String, index: true, unique: true },
enabledPlugins: [
{ type: Schema.Types.ObjectId }
],
delete: { type: Boolean, default: false }
}, {
timestamps: true
});
const Template = mongoose.model('Template', templateSchema);
module.exports = Template;
But When I want to get templates, I get the wrong timestamp:
exports.getAllTemplates = async function() {
return await Template.aggregate(
{ $match: { delete: false } },
{ $project: { id: '$_id', _id: 0, name: 1, enabledPlugins: 1, createdAt: 1 } }
);
};
The result like :
[
{
"createdAt": "2017-03-28T17:04:30.502+08:00",
"name": "hello",
"enabledPlugins": [
"58c24f65b363502f907738f9"
],
"id": "58da135cfc80bc44f7653fd4"
}
]
And I found before toJSON, the output has been wrong. I don't use any plugins. All the date type has the same problem.
Thanks, the problem is that I rewrite Date.prototype.toISOString

Resources