Duplicate null key value error MongoDB with Mongoose - node.js

I'm trying to add a user to my users collection and keep getting a duplicate null key value error.
My Users model used to look like this like this:
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
profilePictures: [{
link: {
type: String
}
rank: {
type: Number,
unique: true
}
}],
});
module.exports = User = mongoose.model("users", UserSchema);
Before I changed the pictures field to
...
pictures = []
...
I believe because I saved users under the former schema, it has saved somewhere the model of the object in the pictures array (they would be given an ObjectId when I saved something to that array).
Even though I have changed the field to
pictures = []
I still get this error
E11000 duplicate key error collection: testDB.users index: profilePictures.rank_1 dup key: { profilePictures.rank: null }
When neither profilePictures nor rank fields even exist anymore.
I imagine I can probably just delete the users collection and start again but I want to know if there is a better way to handle this error? Suppose I had 100 users in the users collection – I wouldn't be able to just delete them all.
Thanks!

you added unique property true in your model to profilePictures.rank. on first request it is saving null as you may be not providing rank in your query.
second time it is again trying to save null but it is also marked unique so it is throwing exception.
solution:
remove unique flag from profilePictures.rank
provide unique value for profilePictures.rank

Related

Is it possible to search for keys within an object within a field within a document in mongoDB?

I have a form on a page, I want a user to enter something in the form click submit, then make a request to MongoDB using the input of that form and render parts of that request onto a page, using nodejs, mongoose, and ejs
The schema of the collection has a field that always contains an object and I would like to search for a document in the collection that has a key that matches the input of the form.
The schema of the collection is
const ArrivalTimesSchema = new mongoose.Schema({
postcodeArrivalTimes: {
type: Object,
required: true,
},
workerId: {
type: String,
required: false
},
company: {
type: String,
required: true
},
})
And an example of postcodeArrivalTimes is
postcodeArrivalTimes = {AL95AT:"07:06", DL56EP:"13:06",AL14PL:"19:15"}
So in this case if someone input AL95AT into the input form I would want this document returned, how would I do that?
Not all documents would contain the key AL95AT but there could be multiple and I would like the last.
For this I think I can use .sort({ $natural: -1 }).limit(1) within a find() but I am not sure how to search for the keys within the object within the field.
Thank you for any help!!
let input = "input" //inputKeyValue
let query = {};
query[input] = { $exists: true };
db.collection.find(query).sort({ $natural: -1 }).limit(1)

Mongoose Sync local schema with mongoose document

Im trying to get this going or wondering if this is even necessary. I have a local schema I define for my user profiles. What im trying to do is write a code block that checks my local schema with what the database has. If a field is missing, add a default value.
My goal for this is to be able to add fields locally in my schema and have the database update when I add a new field.
My schema is as follows:
import mongoose, { Schema } from "mongoose";
const reqString = {
type: String,
required: true,
};
const reqNumber = {
type: Number,
required: true,
};
const userProfileSchema = new Schema({
//Discord User ID - Primary Key
_id: reqString,
wallet: reqNumber,
bank: reqNumber,
net_worth: reqNumber,
classID: reqNumber,
});
const name = "core-userprofile";
export default mongoose.models[name] ||
mongoose.model(name, userProfileSchema, name);
I have a class that pulls the user profile for the rest of the code to access. Id like a function in there that looks at the local schema, realizes there isnt classID, figures out its a type of number, and just places 0 there.
I believe from what im understanding I can use update/upsert when accessing it. Im more wondering if there is a way to sync these two and add/delete anything that doesn't match the local version.
Thanks in advance!

How to find an object inside an array inside a mongoose model?

I'm trying to query an object that's inside an item which is inside a mongoose model, when I'm trying to find that object with the find() method or _.find() method, I can't get access to the object for some reason and when I console.log() it, it gives me undefined or when I use array.filter() it gives me an empty array, which means the object that I'm trying to access does not meet the criteria that I give it in the lodash find method, but then when I look at my database I see that the object does actually have the properties to meet the criteria. So I don't know what I'm doing wrong, here's my code: as you can see I'm trying to get the information of the item that the user clicked on and want to see:
router.get("/:category/:itemId", (req, res) => {
console.log(req.params.itemId);
//gives the item id that the user clicked on
console.log(req.params.category);
//gives the name of category so I can find items inside it
Category.findOne({ name: req.params.category }, (err, category) => {
const items = category.items; //the array of items
console.log(items); //gives an array back
const item = _.find(items, { _id: req.params.itemId });
console.log(item); //gives the value of 'undefined' for whatever reason
});
});
The category Schema:
const catSchema = new mongoose.Schema({
name: {
type: String,
default: "Unlisted",
},
items: [
{
name: String,
price: Number,
description: String,
img: String,
dateAdded: Date,
lastUpdated: Date,
},
],
dateCreated: Date,
lastUpdate: Date,
});
well the answer is a little bit obvious, you are using MongoDB and in Mongo you have "_ID" you can use that "_ID" only with Mongoose! so you just have to remove the underscore and that is it! do it like this const item = _.find(items, { id: req.params.itemId });
hope you are doing better.
When I look at your Schema I see that the item field is an array of objects which doesn't have an _id inside so when you create a new instance of catShema it just generates an _id field for the new instance but not for each item inside the items array, just also enter the id of the item in question because according to my understanding, you must also have a model called items in your database
When you save these records in your database, you will generate an element with this structure
{
_id: String, // auto generated
name: String,
items: [ {"name1", "price1", "description1", "imgUrl1", "dateAdded1", "lastUpdated1"},{"name2", "price2", "description2", "imgUrl2", "dateAdded1", "lastUpdated2"}, ...],
dateCreated: Date,
lastUpdate: Date
}
Note : the code provided at the top is only an illustration of the object which will be registered in the database and not a valid code
Here you can notice that there is not a field called _id in the object sent inside the database.
My suggestion to solve this issue is
To create an additional field inside the items array called _id like :
{
...,
items: [
{
_id: {
type: String,
unique : true,
required: true // to make sure you will always have it when you create a new instance
},
...
... // the rest of fields of items
},
...
Now when you create a new instance make sure in the object you enter in the database the _id is recorded when you call the catInstance.save() so inside the catInstance object you have to add the current Id of the element to be able to filter using this field.
Hope my answer helped, if you have any additional questions, please let me know
Happy coding ...

Mongoose find with default value

I have a mongoose model: (With a field that has a default)
var MySchema= new mongoose.Schema({
name: {
type: String,
required: true
},
isClever: {
type: Boolean,
default: false
}
});
I can save a model of this type by just saving a name and in mongoDB, only name can be seen in the document (and not isClever field). That's fine because defaults happen at the mongoose level. (?)
The problem I am having then is, when trying to retrieve only people called john and isClever = false:
MySchema.find({
'name' : 'john',
'isClever': false
}).exec( function(err, person) {
// person is always null
});
It always returns null. Is this something related to how defaults work with mongoose? We can't match on a defaulted value?
According to Mongoose docs, default values are applied when the document skeleton is constructed.
When you execute a find query, it is passed to Mongo when no document is constructed yet. Mongo is not aware about defaults, so since there are no documents where isClever is explicitly true, that results in empty output.
To get your example working, it should be:
MySchema.find({
'name' : 'john',
'isClever': {
$ne: true
}
})

Sails.js & MongoDB: duplicate key error index

I'm using Sails.js (0.9.8) and MongoDB (via the sails-mongo adaptor) to create a collection of pages that can be positioned in a tree-view. I would like to store the path of a page in an array of UUIDs
My model:
module.exports = {
schema: true,
attributes: {
uuid: {
type: 'string',
unique: true,
required: true,
uuidv4: true
},
name: {
type: 'string',
required: true,
empty: false
},
path: {
type: 'array',
required: true,
array: true
}
}
}
It works well when I save a 'root' page (the 'path' property has just one item because it's a root page. Here is what it was saved in MongoDB:
{
_id: ObjectId("52f853e9609fb6c0341bdfcc"),
createdAt: ISODate("2014-02-10T04:22:01.828Z"),
name: "Home Page",
path: [
"a2b23e1f-954b-49a3-91f1-4d62d209a093"
],
updatedAt: ISODate("2014-02-10T04:22:01.833Z"),
uuid: "a2b23e1f-954b-49a3-91f1-4d62d209a093"
}
But when I want to create a 'subpage' below my previous created page (Home Page/Products), I get this error:
MongoError: E11000 duplicate key error index: cms-project.item.$path_1
dup key: { : "a2b23e1f-954b-49a3-91f1-4d62d209a093" }
Here is the data I sent:
{ name: 'Products',
uuid: 'a004ee54-7e42-49bf-976c-9bb93c118038',
path:
[ 'a2b23e1f-954b-49a3-91f1-4d62d209a093',
'a004ee54-7e42-49bf-976c-9bb93c118038' ] }
I probably missed something but I don't know what.
If I store the path in a string instead of an array, it work well, but I find it much less elegant and handy.
Not sure of all the Sails / Waterline parts myself as I've never played with it. But by the error the problem is there is a unique index on your array field.
When you are inserting your second document, you already have one of the values (the parent) in your path field in another document. The unique constraint is not going to allow this. Most certainly for what you are modelling, you do not want this and the index cannot be unique.
I hope that you set this up yourself under the assumption that it meant unique within the array contained in the document. If you did then you know where to look and what to change now. If this is being automatically deployed somehow, then I'm not the one to help.
Change the index to not be unique. You can confirm this through the mongo shell:
use cms-project
db.item.getIndices()
Good luck

Resources