Got duplicate key error dup key: { : undefined } - mongodb

I have an array field called udids in Meteor.users schema, which should contains unique elements. This is how I defined the index using SimpleSchema and Collection2:
new SimpleSchema({
...
udids: {
type: Array,
index: true,
unique: true,
optional: true,
sparse: true,
},
'udids.$': {
type: String,
},
...
})
However, when I start the app, I got this error: E11000 duplicate key error collection: meteor.users index: c2_udids dup key: { : undefined }.
I tried searching for the documents with udids = undefined in the database: db.users.find({ udids: { $type: 6 } }) ($type: 6 for undefined value) but it returns nothing.

The error message is a bit unclear so I had to guess the reason why. I found out that the current database already has some users with udids = []. I'm writing a migration script to unset this field from those users. Hopefully this will help others who have the same problem as me.

I've not tested this, but it should ideally work.
Used Meteor.users as a collection name. You may want to replace it with whichever collection you want to run the validation against.
Made use of custom function to find at least one doc which contains the field's value in udids.
If you don't have access to the collection on the client side, then you can edit the custom function and have it handled asynchronously.
new SimpleSchema({
...
'udids': {
optional: true,
type: [String], // an array of string eg. ['A','B']
custom: function() {
// this.value = current field's value
// Below mongo query will check to see if there is at least one
// mongo doc whose udids contains the currently entered field's value.
// if found, then return the error message.
if (Meteor.users.findOne({
udids: {
$in: [this.value]
}
})) {
return "duplicateMsg";
}
},
...
});
SimpleSchema.messages({ duplicateMsg:"Udid already exists"});

Related

Removing a key value pair from mongoose schema using findOneAndUpdate() method

In the following is the section of code :
Profile is a mongoose shcema object and contains multiple key-value pairs and the function of the code is to update Profile using findOneAndUpdate method passing in profileFields to $set which contains the new key-value pairs.
let profile = await Profile.findOne({ user: req.user.id });
if (profile) {
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
);
console.log(profile);
return res.json(profile);
}
This code works fine when a value for a key is changed.
eg. Profile.githubusername was abcd and is changed by passing profileFields(in which githubusername is xyz) to $set in the findOneAndUpdate method.
But the code fails when a key-value pair is completely removed.
eg. profileFields object does not contain githubusername key.
In such case the earlier previously stored value of Profile.githubusername persists.
But I need all existing information for profile to be replaced by profileFields such that if a key-value pair is missing from profileFields it is also removed from profile.
Is there a way to achieve this?
TIA
Edit :
I added the following before making the call to findOneAndUpdate(). But this still doesn't work.
let profile = await Profile.findOne({ user: req.user.id });
// for (key in profile)
// console.log(key);
for (key in profile) {
if (Object.keys(profileFields).indexOf(key) === -1) {
console.log('missing key: 'key);
profileFields[key] = '';
}
}
When I console.log(profile) I get:
{
skills: [ 'HTML' ],
_id: 60142f8f9a5bff1f08653478,
user: 60142dc89a5bff1f08653477,
company: 'Self Employed',
bio: 'Useless international',
status: 'Student or Learning',
experience: [],
education: [],
date: 2021-01-29T15:53:51.693Z,
__v: 10,
location: 'Ahemdabad, Gujrat, India',
githubusername: 'k'
}
From what I understand skills, _id, user, company, bio ... githubusername are the only keys in this object.
But on running a for (key in profile) loop I get a lot a other keys as well ,some are :
$__
isNew
errors
$locals
$op
_doc
$init
db
discriminators
schema
collection
$__originalValidate
$__save
$__validate
$__remove
$__deleteOne
$__init
$isMongooseModelPrototype
$__handleSave
save
$__delta
$__version
increment
$__where
remove
delete
How can I loop through only the user defined keys?
You can try:
delete mongooseObject["$init"]
it will delete your key and then u can manipulate other keys

Meteor Upsert Syntax with Nested Values

I am having trouble trying to get a Collection.upsert to work in Meteor 1.4.3.2.
My app pulls in active listings from eBay and inserts them into the database if they don't already exist, otherwise it updates the listing that is already stored. So, what I am trying is the following in a meteor method:
let upsertObj = {$set: {}};
const account = ListingAccounts.findOne( ... );
if (!account) // throw an error because account info is required by schema
upsertObj.$set['account.id'] = account._id;
upsertObj.$set['account.username'] = account.username;
upsertObj.$set['account.nickname'] = account.nickname;
// ... also gets other listing data such as listingId, title, condition, etc...
return Listings.upsert({listingId: eBayListingID}, upsertObj);
There are other values that are nested similarly to the account details above, and they all seem to work. I've logged the final upsertObj object and the values are valid and comply with my schema (SimpleSchema), but just for good measure, here is an excerpt of the final upsert object I am logging on the server just before the upsert happens:
{ '$set':
{ 'account.id': 'trustmethisisvalidstring',
'account.username': 'ValidAccountNameString',
'account.nickname': 'ValidAccountNicknameString',
/* more name:values below this */
}
}
Here is an excerpt from my schema (aldeed:simple-schema 1.5.3)
ListingsSchema = new SimpleSchema({
account: {
type: Object
},
"account.id": {
type: String,
optional: true // added after question asked
},
"account.username": {
type: String,
optional: true // added after question asked
},
"account.nickname": {
type: String,
optional: true // was always optional
},
...
});
I am receiving the error on the client with the following details:
[{"name":"account.id","type":"required","value":null},{"name":"account.username","type":"required","value":null}]
with the reason reason: "Id is required"
This is the first time I've tried using upsert and I can't help but feel I am missing the mark on something. Maybe my syntax is off, or maybe I'm just not using bracket notation correctly? I don't know, the Meteor docs unfortunately do not have any examples that I could find.
Any assistance or clarification on using Upsert would be super appreciated, thank you!

Duplicate Key Error on MongoDB Model, Even When Model is Not Enforcing Uniqueness for that Value

In my app I have an endpoint that allows a user to create a new document by simply passing something like this:
{ name: { long: "some name" } }
Now, the relevant portion of the model for this document looks like this:
name: {
long: {
type: String,
trim: true
},
short: {
type: String,
trim: true
}
}
As you can see, I don't have "short" set to "unique: true". However, the user is getting this error:
"errmsg": "E11000 duplicate key error collection: hr.agencies index: name.short_1 dup key: { : null }"
So, clearly the problem here is that once you have more than one "name.short" with a value of null, its producing a dupe error. However, since I don't have unique set to true in the model, I'm not sure why it's enforcing this as a rule.
What could the issue be here, and how can I resolve it? Is there a way I can explicitly say, don't enforce uniqueness on this field?
Try to remove the index from the short key using
db.collection.dropIndex({ "name.short": 1 })

Lokijs: Inserting document with unique key violation

I am running the latest, as of 5.3.2016, minified Lokijs from Lokijs.org and NW.js v0.12.3-win-x64. I have a document already saved in Lokijs:
"collections":[{"name":"admins","data":[{"username":"erik","meta":{"revision":1,"created":1459028934981,"version":0,"updated":1462333795190},"$loki":1}],"idIndex":[1],"binaryIndices":{},"constraints":null,"uniqueNames":["username"],"transforms":{},"objType":"admins","dirty":true,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableChangesApi":true,"autoupdate":false,"ttl":{"age":null,"ttlInterval":null,"daemon":null},"maxId":2,"DynamicViews":[],"events":{"insert":[null],"update":[null],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[null],"delete":[null],"warning":[null]},"changes":[],"username":{"name":"username","regExp":{}}}.
I am trying to generate an error when I attempt to insert a duplicate key value. I have added a unique constraint on the 'username' key in this collection and have verified the collection.uniqueNames array contains 'username'.
When I run the code below, as expected, no additional documents are inserted into the collection.data array and the database is saved. However, no errors are generated. Also, when I console.log the document object after the insert method has run, it changes to:
Object {username: "erik", meta: Object, $loki: 2}.
When I change the key value to something else, the unique document is then inserted and saved properly.
How do I go about generating an error when attempting to insert a document containing key(s) that violate unique constraints? Thank you.
insertDocument: function(objParameters) {
var collection = objParameters.insert.collection;
collection.ensureUniqueIndex('username');
var document = {username: ''};
document.username = 'erik';
collection.on('error', function(err) {
return console.log(err);
});
collection.insert(document);
return thisModule.$body.triggerHandler('app.database.save');
}
EDIT: loki.db to test clone
{"filename":"loki.db","collections":[{"name":"test","data":[{"name":"erik","meta":{"revision":0,"created":1462493328062,"version":0},"$loki":1}],"idIndex":[1],"binaryIndices":{},"constraints":null,"uniqueNames":["name"],"transforms":{},"objType":"test","dirty":true,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"transactional":false,"cloneObjects":true,"cloneMethod":"parse-stringify","asyncListeners":false,"disableChangesApi":true,"autoupdate":false,"ttl":{"age":null,"ttlInterval":null,"daemon":null},"maxId":2,"DynamicViews":[],"events":{"insert":[null],"update":[null],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[null],"delete":[null],"warning":[null]},"changes":[]}],"databaseVersion":1.1,"engineVersion":1.1,"autosave":false,"autosaveInterval":5000,"autosaveHandle":null,"options":{},"persistenceMethod":"fs","persistenceAdapter":null,"verbose":false,"events":{"init":[null],"loaded":[],"flushChanges":[],"close":[],"changes":[],"warning":[]},"ENV":"NODEJS"}
Code to test clone:
var loki = require('lokijs-1.3.min.js');
var db = new loki();
var collection = db.addCollection('test', {
clone: true,
unique: 'name'
});
collection.on('error', function(error) {
return console.log(error);
});
collection.insert({ name: 'erik'});
collection.insert({ name: 'erik'});
db.saveDatabase();
If you don't use clone: true then you need to call coll.update(document) to force index recomputation, which will trigger the error.

Mongoose/MongoDB throwing duplicate key error on save?

According to MongoDB's documentation a call to save will create a new document, or update an existing document if _id is provided. Mongoose's documentation is less detailed and does not go into whether it will insert or update.
I am attempting to use Mongoose's save function to update a document, but I keep getting the error:
{"error":{"name":"MongoError","code":11000,"err":"insertDocument ::
caused by :: 11000 E11000 duplicate key error index:
staging.participants.$_id _ dup key: { :
ObjectId('5515a34ed65073ec234b5c5f') }"}}
Does Mongoose's save function perform an upsert like MongoDB's save function or is it just performing an insert?
What defines whether the save will be an insert or an update is the isNew flag, as you can see here.
This flag is set automatically to false when the document instance is returned from a find query (or any of its variations). If you are instantiating the document manually, try setting this flag to false before saving it:
var instance = new Model({ '_id': '...', field: '...' });
instance.isNew = false;
instance.save(function(err) { /* ... */ });
There is also an init function, that will initialize the document and automatically set isNew to false:
var data = { '_id': '...', field: '...' };
var instance = new Model();
instance.init(data, {}, function(err) {
instance.save(function(err) { /* ... */ })
});