Unable to insert into subdocument - node.js

I have the following schema
var ChildSchema = new Schema({
name: String,
value: String
});
var ParentSchema = new Schema({
children: [ChildSchema]
});
Now, I wish to insert entries into parent.children.
I did the following:
parentRecord.children.push({
name:"foo",
value: "bar"
});
When I use a console.log, I can see here that the record has been successfully added into the parent record's children property. It also has been give an ID.
Now, I attempt to save the record:
parentRecord.save(myCallback);
While the save is a success, I see that the entry was not added into the children property.
I even tried to use parentRecord.markModified("children"); but that also does not help
I have also ensured that I declare the ChildSchema before I declare the ParentSchema.
I am at my wits end trying to figure out what's wrong. I have set the debug property of mongoose to true. I can see that it's identifying the new entry but I just can't see it getting saved in my database.
Following is the output from the debug messages:
Mongoose: parentRecord.update({ _id: ObjectId("5551895182d9adbe1da34d6a") }) { '$inc': { __v: 1 }, '$set': { anotherField: 'anotherValue' }, '$pushAll': { fields: [ { _id: ObjectId("55518c682a0744dc20f1473b"), value: 'bar', name: 'foo' } ] } } {}
Any hints on what else I need to do to get the entry to save?
I am using mongoose 3.8.12

From what I can tell by the change log it looks like this was an issue that was resolved in version 3.8.13. You may want to try upgrading.
https://github.com/Automattic/mongoose/issues/2082

Related

Save entity with id created in code, mongoose

How can I do to pass the id of a document from outside and not that mongoose generates it?
I need the objects to be stored with the id I tell them, but mongoose overwrites it and saves it with the one he wants. I tried several ways now and nothing happens.
It is an entity that I am distributing through events in several databases, so I need it to be stored with the id I want to maintain the integrity of the data.
Now I have this and it says "document must have an _id before saving", but the id I have already put it, does not recognize it.
The scheme is like this:
const schema = new Schema({
_id: { type: String },
name : { type: String },
});
I also tried with this, and the error is the same:
const schema = new Schema({
_id: { type : String },
name : { type: String },
},
{
_id: false
});
I am passing the object like this:
Item.create({ _id: 'my uuid here', name: 'something' });
but when it is saved it remains with the id generated by mongoose replacing mine, that is, it changes it to me with a _id: '5twt563e3j5i34knrwnt43w'
Your syntax should work, but sometimes mongoose acts weird.
You can try this syntax (works on my project) :
const item = new Item({ name: 'something' });
item._id = 'my uuid here';
await item.save();
Instead of using a random uuid, you need to use a mongoDB objectID. Mongoose can also create that,
var mongoose = require('mongoose');
var id = mongoose.Types.ObjectId();
Store this id in the collection,
Item.create({ _id: id, name: 'something' });

mongoose: Insert a subdocument NOT an array

I am struggling to insert a document inside another document. I've looked at all the entries like this but they aren't quite what I am looking for.
Here is the scenario:
I have a common document that has its own schema. Lets call it a related record:
(function(){
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var relatedRecordSchema = new Schema({
params: {
recordId: Schema.Types.ObjectId,
recordType: String,
recordTitle: String
},
metadata: {
dateCreated: {type: Date, default: Date.now}
}
},{ _id : false });
mongoose.model('RelatedRecord', relatedRecordSchema);
})();
I have no trouble inserting this in an ARRAY inside document that require it. I.e its configured this way:
//Embedded
relationships: {
following: [mongoose.model('RelatedRecord').schema],
followers: [mongoose.model('RelatedRecord').schema],
blocked: [mongoose.model('RelatedRecord').schema]
}
This works perfectly.
The scenario that does not work is where there is a single related record, lets say the source of a notification:
var notificationSchema = new Schema({
params: {
title: String,
imageUrl: String,
source: mongoose.model('RelatedRecord').schema
},
metadata: {
dateCreated: { type: Date, default: Date.now },
dateViewed: Date
}
});
So when I am creating the notification I try and assign the previously prepared RelatedRecord
returnObj.params.source = relatedRecord;
The record appears during a debug to be inserted (it is inside a _docs branch but far deeper than I would expect) but when the object is saved (returnObj.save()) the save routine is abandoned without error, meaning it does not enter into the callback at all.
So it looks to me that i'm confusing mongoose as the dot assignment is forcing the subdoc into the wrong location.
So the question is simple:
How do I set that subdocument?
What the question isn't:
No I don't want to populate or advice on how you would solve this problem differently. We have sensible reasons for doing things how we are doing them.
Cheers
b
As Hiren S correctly pointed out:
1) Sub-Docs = array, always. Its in the first line in the docs :|
2) By setting the type to mixed, assignment of the object worked.
I'm a dumdum.

Not able to persist array of objects in mongo using mongoose

I'm trying to persist an array of objects in a document using mongoose. I have tried multiple times but it's not persisting array in document. It places an empty array in document.
Following is my Schema:
var ProfileSchema = new Schema({
name: String,
PagesData: [{
pageAccessToken: {type: String, get: decryptText, set: encryptText},
category: String,
name: String,
id: String,
perms: [String]
}]
});
module.exports = mongoose.model('Profile', ProfileSchema);
I'm trying to save a document with an array of objects using following query:
var newProfile = new Profile();
newProfile.name = "someName";
newProfile.PagesData = [ { pageAccessToken: 'someToken',
category: 'Bags/Luggage',
name: 'someBrandName',
id: '12345',
perms:
[ 'ADMINISTER',
'EDIT_PROFILE',
'CREATE_CONTENT' ] } ];
newProfile.save(function(err, result, numAffected){
if(err) {
console.log(err);
res.send(500, "Error");
}
console.log(result);
res.send(200, "Success");
});
I tried debugging the mongo commands using
require('mongoose').set('debug', true)
On Debug logs it shows, empty array during insert command execution.
Can anyone please tell me how can I store this array of object in my schema ?
Thanks,
Update:
It's been too long and I'm still not able to figure out the root cause of the problem. There is a long thread going on github for this.
https://github.com/Automattic/mongoose/issues/3249
I would like other experts to please take a look and suggest me some way by which I can solve the issue. I'm really stuck at this.
Update 2:
None of the solution worked for me so far, so I decided to modify the schema only to meet my requirements. This resulted in a different problem:
I want to create a map with a objectId as key and an array of string values as its value. The closest that I can get is:
var schema = new Schema({
map: [{myId: {type:mongoose.Schema.Types.ObjectId, ref: 'MyOtherCollection'}, values: [String]}]
});
But somehow this is not working for me. When I perform an update with {upsert: true}, it is not correctly populating the key: value in the map. In fact, I'm not even sure if I have declared the schema correctly.
Can anyone tell me if the schema is correct ? Also, How can I perform an update with {upsert: true} for this schema?
Also, if above is not correct and can;t be achieved then how can I model my requirement by some other way. My use case is I want to keep a list of values for a given objectId. I don't want any duplicates entries with same key, that's why picked map.
Please suggest if the approach is correct or should this be modelled some other way?
Thanks
I tried the exact code you have provided here and it's working for me. I am not sure what is causing the issue for you. Until and unless we get the same issue, it's very difficult to rectify it.
Here are few suggestions which you might try:
Create a simple schema and try storing the object, that way you can
figure it out if it has to do something with the schema.
You can try out your schema in a sample app to find if some
dependency is causing the problem.
Once you know where exactly the problem is, you would be able to figure out a solution too. I hope it helps.
I tested this and the insert works for me using the below:
(I had to remove the get: decryptText, set: encryptText)
var n = { name: "Testing for mongoose", PagesData : [{ pageAccessToken: 'someToken',
category: 'Bags/Luggage',
name: 'someBrandName',
id: '12345',
perms:
[ 'ADMINISTER',
'EDIT_PROFILE',
'CREATE_CONTENT' ] } ] }
Profile.create(n, function (err) {
if (!err) {
return 'records saved successfully';
}
else {
return error on save:' + err;
}
});
To create multiple pageDatas you can use it as an embedded collection instead of using arrays.
The Schema will be as follows:
var PagesDataSchema = new Scheme({
pageAccessToken: {type: String, get: decryptText, set: encryptText},
category: String,
name: String,
id: String,
perms: [String]
})
var ProfileSchema = new Schema({
name: String,
PagesData: [PagesDataSchema]
});
module.exports = mongoose.model('Profile', ProfileSchema);
Reference: http://mongoosejs.com/docs/subdocs.html
For Saving the document you can use like.
exports.save = function(req,res){
var test = new ProfileSchema; // new object for ProfileSchema domain.
test.name= req.body.name;
if(req.body.PagesData){
req.body.PagesData.forEach(function(page){ // For every element of pageData from client.
test.PagesData.push(page) // This pushes each and every pagedata given from the client into PagesData.
})
}
test.save(function (saveErr, saved) { // Saves the new document into db.
if (saveErr) {
console.log(saveErr)
return;
}
res.status(HttpStatus.OK).json(saved);
});
};
Hope this helps.
Have you tried
Profile.create({
name: "someName",
PagesData: [
{
pageAccessToken: 'someToken',
category: 'Bags/Luggage',
name: 'someBrandName',
id: '12345',
perms: [
'ADMINISTER',
'EDIT_PROFILE',
'CREATE_CONTENT'
]
}
]
}, function(err, profile) {
// do your stuff
})
?

How to find and update subdocument within array based on parent property

I need to find a subdocument which is inside an array, based on its own user_id property and its parent's my_id property
These are the schemas I have for my model (Conversation):
var listSchema = mongoose.Schema({
user_id: Number,
property: Boolean,
});
var conversationSchema = mongoose.Schema({
my_id: Number,
list: [listSchema]
});
After browsing through mongoose's documentation and some similar questions here on SO, I've tried the following (which seems to me like that it should work):
Conversation.findOneAndUpdate(
{ "my_id": 8, "list.user_id": 16 },
{
"$set": {
"list.$.property": false
}
},
function(err, doc) {
console.error("Error:", err);
console.log("Doc:", doc);
}
);
But it gives me this output and the documents are not being updated at all:
Error: null
Doc: null
What am I missing here? Any help is appreciated, thanks in advance!
I've finally figured out what was going on:
I was saving the user_id property as a String to MongoDB so I tried changing this part of the query to:
"list.user_id": "16"
instead of:
"list.user_id": 16
Still didn't work, but then I figured out that I was defining user_id as Number in listSchema so I changed that to String:
var listSchema = mongoose.Schema({
user_id: String,
property: Boolean,
});
And now it works, it doesn't matter if I use "16" or 16 in the query, I think that mongoose will try to find a String now instead of a Number like it was doing before

Saving a value into an array of objects in Express/Angular/Node

I'm still getting the hang of Express/Angular and how they work together to post to the server. I'm using the MEAN stack in my sample application.
The Schema for the object I'm trying to post looks like this in Express.
First define the 'Version' Schema:
var VersionSchema = new Schema({
title: {
type: String,
default: '',
trim: true
},
content: {
type: String,
default: '',
trim: true
},
submitted: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
The Version Schema is used in my Draft Schema. When a user creates a draft, it becomes a Version item in the versions array. When the draft is updated, it creates a new array item so all versions of the draft are saved.
var DraftSchema = new Schema({
versions: [VersionSchema],
});
The Draft Schema is set up as an Angular Service and injected into my controller. The service is boilerplate code for creating a $resource though so shouldn't be necessary.
I have two controllers to create the Draft object and save to Mongo: one with Angular, one with Express.
Angular controller:
$scope.create = function() {
var version = {
title: this.title,
content: this.content
};
var draft = new Drafts({
versions: [version]
});
draft.$save(function(response) {
$location.path("drafts/" + response._id);
});
};
In the angular controller I'm passing the title and contents to be saved to the Draft. As I understand it, you should not use an Angular controller to pass user information to the server. So this is handled by Express in the controller below.
Express controller:
exports.create = function(req, res) {
var draft = new Draft(req.body);
draft.versions = [req.user]; // Here is where my problem is, trying to save user
draft.save(function(err) {
if (err) {
return res.send('users/signup', {
errors: err.errors,
draft: draft
});
} else {
res.jsonp(draft);
}
});
};
You can see in my comment above where my problem is. I've looked through docs, SO questions, etc for the correct way to set my User property to the Versions array item being created here.
Note that if I move the User from the Version Schema to the Draft Schema and use:
draft.user = req.user;
To save the user then it works just fine. But I want the user to be saved into the VersionSchema.
To address Erick's comment below, this is a JSON representation of what I want my Draft model to look like. Versions is an Array because I want a new array item to be created each time the draft is updated.
[{
_id: 4h55542j232555000441,
versions: [
{
title: “A really great title”,
body: “On that day the people….”,
user: 5234523452349589hh23523,
submitted: Date
}
]
}];
draft.versions = [req.user]
Does the following: replace the versions array containing a version object with a new array containing the user object. This is not what you want.
As I see it, draft.versions has the following content:
[
{
title: '...',
content: '...'
}
]
To add a user id you need to do the following steps:
get the version object from the versions array
assign a new property to the version object and give it a value of user._id
var version = draft.versions[0]
version['user'] = req.user._id

Resources