Suppose I already have some data in database:
{
id: 001,
title: "title_1"
}
{
id: 002,
title: "title_2"
}
{
id: 003,
title: "title_3"
}
then I want to insert some new documents:
{
id: 003 // id repeat
title: "title_4"
}
{
id: 004
title: "title_5"
}
but I don't want to insert the { id:003 } item, because some guy in the database already has the same id.
So, how can I let the MongoDB ignore the repeat value(with specified key) item when I insert new data?
For this you have to create unique index on id. You have to try like this:
db.collection.ensureIndex( { id: 1 }, { unique: true } )
I think you could use a Unique Index
Apart from putting this as unique index as it was suggested earlier, you can just insert them with a different key. Instead of id key as you already have, you can insert them with unique primary key _id (you can use your own unique _id field if you want so http://docs.mongodb.org/manual/core/document/#the-id-field)
Related
I want to insert to new field and data in existing document, if there is no data in it.
if (repoData.detailViewCounter == undefined) {
console.log('create 0')
Repo.findOneAndUpdate({
'owner.login': userId,
'name': pageId
}, {
detailViewCounter: 0
},
{new: true, upsert: true})
}
So When condition like this, and there is no detailViewCounter field, insert new field with number 0.
{
'owner.login': userId,
'name': pageId
}
But When I run this code and check the MongoDB Compass, there is still no data.
And I also create repo schema detailViewCounter with type:Number
change in option upsert: false
one major problem is field name "owner.login" this is causing the issue, this will search in object owner: { login: userId } but in actual we have string "owner.login", so this is not able to find any matching document, and this will not update record.
you can check after removing condition on field owner.login, it will work
Repo.findOneAndUpdate({
'name': pageId
},
{ detailViewCounter: 0 },
{ new: true, upsert: false }
)
Look at MongoDB restriction on field names, and good question in SO.
I've recently started using MongoDB using Mongoose (from NodeJS), but now I got stuck updating a subdocument in an array.
Let me show you...
I've set up my Restaurant in MongoDB like so:
_id: ObjectId("5edaaed8d8609c2c47fd6582")
name: "Some name"
tables: Array
0: Object
id: ObjectId("5ee277bab0df345e54614b60")
status: "AVAILABLE"
1: Object
id: ObjectId("5ee277bab0df345e54614b61")
status: "AVAILABLE"
As you can see a restaurant can have multiple tables, obviously.
Now I would like to update the status of a table for which I know the _id. I also know the _id of the restaurant that has the table.
But....I only want to update the status if we have the corresponding tableId and this table has the status 'AVAILABLE'.
My update statement:
const result = await Restaurant.updateOne(
{
_id: ObjectId("5edaaed8d8609c2c47fd6582"),
'tables._id': ObjectId("5ee277bab0df345e54614b61"),
'tables.status': 'AVAILABLE'
},
{ $set: { 'tables.$.status': 'CONFIRMED' } }
);
Guess what happens when I run the update-statement above?
It strangely updates the FIRST table (with the wrong table._id)!
However, when I remove the 'tables.status' filter from the query, it does update the right table:
const result = await Restaurant.updateOne(
{
_id: ObjectId("5edaaed8d8609c2c47fd6582"),
'tables._id': ObjectId("5ee277bab0df345e54614b61")
},
{ $set: { 'tables.$.status': 'CONFIRMED' } }
);
Problem here is that I need the status to be 'AVAILABLE', or else it should not update!
Can anybody point me in the wright direction with this?
according to the docs, the positional $ operator acts as a placeholder for the first element that matches the query document
so you are updating only the first array element in the document that matches your query
you should use the filtered positional operator $[identifier]
so your query will be something like that
const result = await Restaurant.updateOne(
{
_id: ObjectId("5edaaed8d8609c2c47fd6582"),
'tables._id': ObjectId("5ee277bab0df345e54614b61"),
'tables.status': 'AVAILABLE'
},
{
$set: { 'tables.$[table].status': 'CONFIRMED' } // update part
},
{
arrayFilters: [{ "table._id": ObjectId("5ee277bab0df345e54614b61"), 'table.status': 'AVAILABLE' }] // options part
}
);
by this way, you're updating the table element that has that tableId and status
hope it helps
The schema is like this. it's a shopping cart with items:
export interface Cart extends mongoose.Document {
userId: string;
total: number;
count: number;
status: string;
items: [
{
itemId: string;
itemName: string;
count: number;
price: number;
itemTotal: number;
},
];
}
if you look at the mondodb data, there is an _id to each of the members in items array.
I have this _id, and i want to remove an item by that _id.
The problem is, it's typescript, and _id is not part of the schema.
Here is the code i use to delete an item:
const cart = await this.cartModel.findOneAndUpdate(
{ _id: dto.cartId },
{ $pull: { items: { _id: '1234567890' } } },
{ new: true },
);
Which means, in that specific cart, find the item with _id equals to 1234567890, and delete it.
BUT the _id has red squiggly, as it is not part of my schema.
How can I solve this?
It shoulds be id not _id. Because _id is an object. But our query cannot send object to params. So, it should be a hexString.
You can change your entity _id to id by:
#ObjectIdColumn()
#Transform(id => id.toString())
id: string;
So that, you can use id as hexString anywhere. Hope it helps
For lack of better solution, i have bypassed this issue by adding a text field called timeStamp. when an item is added to the cart, i push the current time (in ms) to that field, and that is unique enough to distinguish between entries in a shopping cart. In case you wonder, itemId is not good enough, as people can have the same item in 2 or more lines, with different details. I have added of course the new field to my schema, so typescript is not complaining ;)
In my Movie schema, I have a field "release_date" who can contain nested subdocuments.
These subdocuments contains three fields :
country_code
date
details
I need to guarantee the first two fields are unique (primary key).
I first tried to set a unique index. But I finally realized that MongoDB does not support unique indexes on subdocuments.
Index is created, but validation does not trigger, and I can still add duplicates.
Then, I tried to modify my update function to prevent duplicates, as explained in this article (see Workarounds) : http://joegornick.com/2012/10/25/mongodb-unique-indexes-on-single-embedded-documents/
$ne works well but in my case, I have a combination of two fields, and it's a way more complicated...
$addToSet is nice, but not exactly what I am searching for, because "details" field can be not unique.
I also tried plugin like mongoose-unique-validator, but it does not work with subdocuments ...
I finally ended up with two queries. One for searching existing subdocument, another to add a subdocument if the previous query returns no document.
insertReleaseDate: async(root, args) => {
const { movieId, fields } = args
// Searching for an existing primary key
const document = await Movie.find(
{
_id: movieId,
release_date: {
$elemMatch: {
country_code: fields.country_code,
date: fields.date
}
}
}
)
if (document.length > 0) {
throw new Error('Duplicate error')
}
// Updating the document
const response = await Movie.updateOne(
{ _id: movieId },
{ $push: { release_date: fields } }
)
return response
}
This code works fine, but I would have preferred to use only one query.
Any idea ? I don't understand why it's so complicated as it should be a common usage.
Thanks RichieK for your answer ! It's working great.
Just take care to put the field name before "$not" like this :
insertReleaseDate: async(root, args) => {
const { movieId, fields } = args
const response = await Movie.updateOne(
{
_id: movieId,
release_date: {
$not: {
$elemMatch: {
country_code: fields.country_code,
date: fields.date
}
}
}
},
{ $push: { release_date: fields } }
)
return formatResponse(response, movieId)
}
Thanks a lot !
So I have found quite few related posts on SO on how to update a field in a sub array, such as this one here
What I want to achieve is basically the same thing, but updating a field in a subarray dynamically, instead of just calling the field name in the query.
Now I also found how to do that straight in the main object, but cant seem to do it in the sub array.
Code to insert dynamically in sub-object:
_.each(data.data, function(val, key) {
var obj = {};
obj['general.'+key] = val;
insert = 0 || (Documents.update(
{ _id: data._id },
{ $set: obj}
));
});
Here is the tree of what I am trying to do:
Documents: {
_id: '123123'
...
smallRoom:
[
_id: '456456'
name: 'name1'
description: 'description1'
],
[
...
]
}
Here is my code:
// insert a new object in smallRoom, with only the _id so far
var newID = new Mongo.ObjectID;
var createId = {_id: newID._str};
Documents.update({_id: data._id},{$push:{smallRooms: createId}})
And the part to insert the other fields:
_.each(data.data, function(val, key) {
var obj = {};
obj['simpleRoom.$'+key] = val;
console.log(Documents.update(
{
_id: data._id, <<== the document id that I want to update
smallRoom: {
$elemMatch:{
_id : newID._str, <<== the smallRoom id that I want to update
}
}
},
{
$set: obj
}
));
});
Ok, having said that, I understand I can insert the whole object straight away, not having to push every single field.
But I guess this question is more like, how does it work if smallRoom had 50 fields, and I want to update 3 random fields ? (So I would NEED to use the _each loop as I wouldnt know in advance which field to update, and would not want to replace the whole object)
I'm not sure I 100% understand your question, but I think the answer to what you are asking is to use the $ symbol.
Example:
Documents.update(
{
_id: data._id, smallRoom._id: newID._str
},
{
$set: { smallroom.$.name: 'new name' }
}
);
You are finding the document that matches the _id: data._id, then finding the object in the array smallRoom that has an _id equal to newId._str. Then you are using the $ sign to tell Mongo to update that object's name key.
Hope that helps