Mongoose duplicate key error in nested schema - database

I currently have the following schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Comments = new Schema({
authorId: {
type: Schema.Types.ObjectId,
unique: false
},
commentBody: {
type: String
}
});
//Create schema
const GroupSchema = new Schema({
name:{
type: String,
required: true
},
comments: [Comments]
});
module.exports = Group = mongoose.model('group', GroupSchema);
I can insert the first group with no errors, but as soon as i try to add the second one i get this error:
{
"error": {
"name": "MongoError",
"message": "E11000 duplicate key error collection: app-idiomas.groups index: comments.authorId_1 dup key: { : null }",
"driver": true,
"index": 0,
"code": 11000,
"errmsg": "E11000 duplicate key error collection: app-idiomas.groups index: comments.authorId_1 dup key: { : null }"
}
}
So, as i suppose, the problem is with the "Comments" schema and i have searched about nested schema to see if i can solve this problem. I have tried to use "default" and "sparse" attribute, but no success.
Finally i decided to make a test and remove the Comments schema and it's reference in Groups Schema just to confirm that everything is OK. I erased all my database and added the first group (now without any comments attribute) and i still get the error whenever i try to add the second one. I just don't know why.
Any help ?
UPDATE
I didn't have time in these last days, but finally i found what the problem was. Probably when i was creating the Comments Schema i may have set the authorId to be unique and because of that MongoDB created an index for this attribute. I don't know much about MongoDB and that's why i hadn't checked before. But here is where i found the index and removed it:
Location of "indexes" tab in MongoDB

This problem has to be with record in the database.
But as you said you cleared the database, the problem looks weird.
Just make a check another time whether you deleted the correct database i.e the one you are using in your api.

Related

Meteor inserting into a collection schema with array elements

Hi I created a SimpleSchema for a Mongo collection which has a variable number of sub-documents called measurables. Unfortunately it's been a while since I've done this and I can't remember how to insert into this type of schema! Can someone help me out?
The schema is as follows:
const ExerciseTemplates = new Mongo.Collection('ExerciseTemplates');
const ExerciseTemplateSchema = new SimpleSchema({
name: {
type: String,
label: 'name',
},
description: {
type: String,
label: 'description',
},
createdAt: {
type: Date,
label: 'date',
},
measurables: {
type: Array,
minCount: 1,
},
'measurables.$': Object,
'measurables.$.name': String,
'measurables.$.unit': String,
});
ExerciseTemplates.attachSchema(ExerciseTemplateSchema);
The method is:
Meteor.methods({
addNewExerciseTemplate(name, description, measurables) {
ExerciseTemplates.insert({
name,
description,
createdAt: new Date(),
measurables,
});
},
});
The data sent by my form for measurables is an array of objects.
The SimpleSchema docs seem to be out of date. If I use the example they show with measurables: type: [Object] for an array of objects. I get an error that the the type can't be an array and I should set it to Array.
Any suggestions would be awesome!!
Many thanks in advance!
edit:
The measurable variable contains the following data:
[{name: weight, unit: kg}]
With the schema above I get no error at all, it is silent as if it was successful, but when I check the db via CLI I have no collections. Am I doing something really stupid? When I create a new meteor app, it creates a Mongo db for me I assume - I'm not forgetting to actually create a db or something dumb?
Turns out I was stupid. The schema I posted was correct and works exactly as intended. The problem was that I defined my schema and method in a file in my imports directory, outside both client and server directories. This methods file was imported into the file with the form that calls the method, and therefore available on the client, but not imported into the server.
I guess that the method was being called on the client as a stub so I saw the console.log firing, but the method was not being called on the server therefore not hitting the db.
Good lesson for me regarding the new recommended file structure. Always import server side code in server/main.js!!! :D
Thanks for your help, thought I was going to go mad!

google cloud datastore API update issue

Following the guidance provided here (https://cloud.google.com/datastore/docs/concepts/transactions), I'm creating an entity with below schema
data: [
{
name: 'created',
value: new Date().toJSON()
},
{
name: 'name',
value: templateObj.name,
excludeFromIndexes: true
}
]
I see this goes thru as expected and notice that the column "name" is not indexed.
Now, I use the transaction and update the entity. Below is the payload
[
{
"property": "active",
"value": false
},
{
"property":"name",
"value":"new updated template"
}
]
Code is exactly the same as documented.
While updating the data, why does it update the schema?
There is really no schema when it comes to Cloud Datastore. It is schemaless. Any time you save (Insert or Update) an entity (regardless of its Kind), you have to specify whether or not the properties in the entity should be indexed. If you do not explicitly set the excludeFromIndexes, the property will be indexed. So, when you create an entity or update an existing entity, make sure to set the excludeFromIndexes to false if you want to keep the property unindexed.

Mongoose schema to require array that can be empty

I have this schema
var StuffSchema = new mongoose.Schema({
_id: { type: String, required: true, unique: true },
name: { type: String, required: true }
});
mongoose.model('Stuff', StuffSchema);
Works fine.
Now I need to add another schema "Cargo" containing this
mystuff: { type:[String], ref: 'Stuff', required:true},
that is, I want mystuff to contain array of ids of Stuff, but this fails with validation error when running this code
mongoose.model('Cargo').create( some data...)
if I use an empty array for the mystuff field.
It seems to work if I change the Cargo schema to
mystuff: { type:[String], ref: 'Stuff'},
but I want the mystuff field to be required and allow empty arrays
What can I do to make this happen?
Empty arrays are created by default (see also this). The attribute required: true requires the array to have at least one element in it (source code). You can remove that attribute to get your desired behavior.
(Aside, mongoose assigns a default _id field with the type ObjectId to all schemas. Declaring it is unnecessary, and using a string is not typical, although certainly allowed.)
Edit Nov 2017: This is a candidate change in Mongoose 5. See https://github.com/Automattic/mongoose/issues/5139.

When to use a nested array versus using a separate collection

I need to use mongoose with dbref but I don't know which design is better for me.
First design:
var user = mongoose.Schema({
name: 'string'
});
var eventSchema = mongoose.Schema({
title: 'string',
propietary_id: 'String',
comments : [{
text: 'string',
user: { type : mongoose.Schema.Types.ObjectId, ref : 'users' },
createdAt: {type: Date, default: Date.now }
}]
});
Second design:
var user = mongoose.Schema({
name: 'string'
});
var eventSchema = mongoose.Schema({
title: 'string',
propietary_id: 'String'
});
var commentSchema = mongoose.Schema({
text: 'string',
event_id : { type : mongoose.Schema.Types.ObjectId, ref : 'events' },
user_id : { type : mongoose.Schema.Types.ObjectId, ref : 'users' },
createdAt: {type: Date, default: Date.now }
});
How it works? On my website there is an event list and if you want to see comments you have to click every event, then angularjs gets all comments (text, user name and user photo) of the selected events.
There are pros and cons with both solutions and the best one for you depends on your usage. Remember that you can produce exactly the same API independent of your design it only comes down to how quickly and easily you can maintain the backend. First some thoughts on both designs:
First design:
First a comment, I wouldn't save comments as a nested document but as an array instead. Otherwise you are limited to one comment per event. Use this schema instead:
comments: [
{
text: { type: String },
user: { type: mongoose.Schema.Types.ObjectId, ref : 'users' },
createdAt: { type: Date, default: Date.now },
}
]
Pros:
No need for multiple collections
You will have the comments returned with the event in the get request which will mean less requests to your backend
No need to map comments to events
Cons:
You will have the comments returned to you with the event, even if you don't want them displayed
If there are a lot of comments to an event, the request response will be pretty large
If you want to remove or edit comments in your array it will be trickier (not impossible though)
Second design:
Pros:
You will have the events and comments separated which means leaner objects
You can much easier extract one comment for edit or delete
You can more easily get events without comments and then request comments at another point
Cons:
You will need to always map comments to events which will mean more code
Two collections will mean two requests usually
Maintenance of another collection
Verdict:
All the pros and cons are judged by how much extra code you need to write. Of course you can always have comments returned with your events in the second design as well but then you will have the extract the comments first and returned them with the event object which will mean extra code to maintain.
I think the second design would work better for you. I'm judging this by your comment that you will only need comments if the user click on an event. I would then be requesting the events first and do another request for comments as soon as the user click on the event, however, having the comments always be returned with the events should make the ui more snappy as the comments will already have been loaded.
It all depends in the end what is more important for you to do with the data. Please let me know if you have any questions on any of the points.

ExtJS: Ext.data.DataReader: #realize was called with invalid remote-data

I'm receiving a "Ext.data.DataReader: #realize was called with invalid remote-data" error when I create a new record via a POST request. Although similar to the discussion at this SO conversation, my situation is slightly different:
My server returns the pk of the new record and additional information that is to be associated with the new record in the grid. My server returns the following:
{'success':true,'message':'Created Quote','data': [{'id':'610'}, {'quoteNumber':'1'}]}
Where id is the PK for the record in the mysql database. quoteNumber is a db generated value that needs to be added to the created record.
Other relevant bits:
var quoteRecord = Ext.data.Record.create([{name:'id', type:'int'},{name:'quoteNumber', type:'int'},{name:'slideID'}, {name:'speaker'},{name:'quote'}, {name:'metadataID'}, {name:'priorityID'}]);
var quoteWriter = new Ext.data.JsonWriter({ writeAllFields:false, encode:true });
var quoteReader = new Ext.data.JsonReader({id:'id', root:'data',totalProperty: 'totalitems', successProperty: 'success',messageProperty: 'message',idProperty:'id'}, quoteRecord);
I'm stumped. Anyone??
thanks
tom
[Responding with an answer instead of a comment for code formatting...]
Some indented formatting will make the difference clear. This (correct) form returns a single object with two properties:
{
'success':true,
'message':'Created Quote',
'data': [{
'id':'610',
'quoteNumber':'1'
}]
}
Your original format returned two separate objects with mismatched properties that cannot be resolved into columns:
{
'success':true,
'message':'Created Quote',
'data': [{
'id':'610'
},{
'quoteNumber':'1'
}]
}
Turns out that the response from the server should look like this:
{'success':true,'message':'Created Quote','data': [{'id':'610','quoteNumber':'1'}]}
A subtle difference, not one that I'm certain I understand.

Resources