Unique and id is getting null in Moongose update/upsert - mongodb

I have one schema like this:
export const HotelSchema = new mongoose.Schema({
name: String,
firstName: String,
email: { type: String, unique: true },
canLogin: Boolean
},
{
collection: "hotels"
}
);
and to add/update I am using this query:
this.hotelModel.updateOne({ _id: hotel._id }, hotel, { upsert: true });
Where hotel object I am passing:
{
"email" : "er.markar#gmail.com",
"name" : "sunny123"
}
But it is inserting duplicate emails with _id as null:
Even I tried findOneAndUpdate. tried autoIndex in the email schema. Still not working.
Am I missing something?

See https://mongoosejs.com/docs/validation.html#the-unique-option-is-not-a-validator
Infact, you should use unique index on a field. That works!

You are passing email and name, but you are not passing "_id", so "hotel._id" will not be found. Instead you should do as follows:
this.hotelModel.updateOne({ email:hotel.email}, hotel, { upsert:true});

Related

MongoDB - how I add a UUID column to existing collection based on values from current entries?

I have 'Users' collection which has two columns, '_id' and 'userName', both of type string.
I want to add third column 'UserId' which will be UUID wrapping the id from _id column.
Tried few ways but without any success.
For example:
{
_id: "fe83f869-154e-4c26-a5db-fb147728820f",
userName: "alex"
}
I want it to be:
{
_id: "fe83f869-154e-4c26-a5db-fb147728820f",
userName: "alex",
UserId: UUID("fe83f869-154e-4c26-a5db-fb147728820f")
}
I tried something like:
db.Users_temp.update(
{},
{ $set: {"UserId": UUID("$_id") } },
false,
true
)
But it results in columns with value UUID("----")
Will appreciate any help.
Ok,
Found a solution to my problem.
db.Users_temp.find().forEach(function(user) {
db.Users_temp.update(
{"_id" : user._id},
{ "$set": {"UserId": UUID(user._id)} }
)
})
this will work
i am not sure why but this works only with set operation as an array rather than as a object
db.Users_temp.update({},[{$set: {'UserId': '$_id'}}])

How to define mongoose schema for nested documents

I need to define the mongoose schema for for nested documents which is given below.
Documents:
"Options":[{"Value":["28","30","32","34","36","38","40","42","44","46"],"_id":{"$oid":"5de8427af55716115dd43c8f"},"Name":"Size"},{"Value":["White"],"_id":{"$oid":"5de8427af55716115dd43c8e"},"Name":"Colour"}]
I was declaring like below but its not working.
const Product = new Schema(
{
Options: [{ value: { _id: ObjectId, Name: String } }]
},
{
timestamps: {
createdAt: "createdAt",
updatedAt: "updatedAt"
},
collection: "products"
}
);
Here I need the schema where if i will directly add/update the same document then it will be added.
You need to modify your schema like this :
{
Options: [ new Schema ({ value: [...], _id: Schema.Types.ObjectId, Name: String })]
}
This is the way to create an array of subdocuments with Mongoose. If you don't use the "new Schema" key words, you are actually creating a field with type "Mixed", which needs a different way to handle updates.
You can also omit the _id, it should be added automatically.
You can find more information on subdocument on this page :
https://mongoosejs.com/docs/subdocs.html
...and on mixed type fields : https://mongoosejs.com/docs/schematypes.html#mixed
...which will explain shortly the problem.
{
Options: [ new Schema ({ _id: mongoose.Types.ObjectId(),value: [String], Name: String } })]
}

OData - Strange index with MongoDB [Mongoose: Cast Error]

I have some MongoDB documents with this schema:
Id: {type: "id", key: true, computed: true, nullable: false},
Name: {type: "string", nullable: false, maxLength: 50}
and these documents are exposed as OData by a small web application (I'm using Express, JayData, and Mongoose).
These are some of those documents:
{ "_id" : ObjectId("5343fd656b9c5c084b8f2a70"), "Name" : "Service74"},
{ "_id" : ObjectId("5343fd656b9c5c084b8f2a6f"), "Name" : "Service73"},
{ "_id" : ObjectId("5343fd656b9c5c084b8f2a6e"), "Name" : "Service72"},
...
If I type this address http://localhost:8080/marketplace/Services('5343fd656b9c5c084b8f2a70') which correspond to Service74 I get this result:
...
<d:Id>NTM0M2ZkNjU2YjljNWMwODRiOGYyYTcw</d:Id>
<d:Name>Service74</d:Name>
...
Of course If I use the Id specified in the result I obtain the same page.
The problem occurs when I try to use the mongoose function findById:
app.post("/addCompare/:id", function(req, res) {
console.log(req.params.id);
Services.findById(req.params.id, function(err, service) {
if(!err) {console.log(service);}
else {console.log(err);}
});
res.send(200);
});
I get this NTM0M2ZkNjU2YjljNWMwODRiOGYyYTcw and then this error:
{ message: 'Cast to ObjectId failed for value "NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5" at path "_id"',
name: 'CastError',
type: 'ObjectId',
value: 'NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5',
path: '_id' }
Where am I wrong? Tell me if I miss some other information...
Thanks.
PS: I found a similar problem here Mongoose: Cast to ObjectId failed, but if I change the model definition for Mongoose (in which actually I don't declare the id) by including this definition:
var serviceSchema = mongoose.Schema({
_id: String,
...
nothing changes...
The 5343fd656b9c5c084b8f2a70 is the internal identifier of the entity that is used on the server-side. This value is base64-encoded over OData, this is why you receive NTM0M2ZkNjU2YjljNWMwODRiOGYyYTcw in the Id field. The entity can be easily retrieved by Id by calling atob(req.params.id) on the received Id.

Update child element on mongodb

I've got a little problem with mongodb update method. This is my (simplified) schemas:
{
profile: {
birthdate: "XXX",
city: "xxx"
},
account: {
username: "...",
password: "....",
visits: 0
}
}
I've got 2000 objects in DB. I want to anonymize datas by removing username values.
I tried this:
db.users.update({}, {$set: account: {username: ""}}, false, true);
That doesn't works, this query remove password field and visits. I understand why, but how to do ?
db.users.update({}, {account: { $set: {username: ""}}}, false, true);
mongo want to assign "$set" field, so that dosen't work.
My question is: how to update descendant fields without removing the entire "account" subdocument ?
(Setting "upsert" to true does the same.)
You should use:
$set:{"account.username":""}
Just wondering why you don't use $unset?

mongoose: myModel.find always return subdocument

var myschema = new Schema({
name: {type:String, default:'fullname'},
subdoc: {
day1: {type:Array, default:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},
day2: {type:Array, default:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}
}
});
var mymodel = Mongoose.model('mytest',myschema);
//mongoose 3.5.6: find
mymodel.find({},{'name'}, function(err,docs){
logger.info("---> " + docs);
});
results:
---> { _id: 512da190ba48050f2e000001, **subdoc: {}**, name: 'fullname' }
Only name field is requested to be returned, but this function always returns subdoc: {}. Can someone explain this?
use mongodb shell, it looks fine
db.mytests.find({},{"name":1})
{ "_id" : ObjectId("512da190ba48050f2e000001"), "name" : "fullname" }
Then I change the model to:
var myschema = new Schema({
name: {type:String, default:'fullname'},
subdoc: [
day1: {type:Array, default:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},
day2: {type:Array, default:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}
] // **note: not {} here**
})
use the same mongoose api find, the result is just what I expected:
--->{ _id: 512da46fffebd24b30000002, name: 'fullname' }
My questions is: Why field 'subdoc' is returned with the former schema?
According to the docs, it appears as if you are a little bit off.
Example:
// name LIKE john and only selecting the "name" and "friends" fields, executing immediately
MyModel.find({ name: /john/i }, 'name friends', function (err, docs) { })
With that, I would do something like this:
myModel.find( {}, 'name', callback);
Edit
To address your comments: In mongodb console, the proper way to format it would be {'name':1, 'friend':1}. Using:
db.collection.find({}, {'name friend'})
will throw an error. To do this properly, you would do:
db.collection.find({}, {'name':1, 'friend':1})
However, if you prefer this way of field selection, mongoose does allow you to do that as well.
myModel.find({}, {'name':1, 'friend': 1}, callback);
See: API Docs