I'm still in the middle of getting familiar with mongoDB queries so my problem might be very easy for you guys.
The problem is -
I have a document as shown in 'document.jpg'
document.jpg
Both of these documents are having one entry '5ac649444f3df45be852df84' under their products array. I want to remove this entry. I have the name of these two documents in an array and also have this entry '5ac649444f3df45be852df84' -
arr = ['andwived', 'QA Infotech']
productId = 5ac649444f3df45be852df84
Now the query I am using is -
enter code here
productId = mongoose.Types.ObjectId(productId)
Org.update(
{
'name':{"$in":[arr]}
},
{
$pull: {'products': productId}
},
callback
)
This is not giving any error but not removing the mentioned id either. Please help.
Try this..
const productId = mongoose.Types.ObjectId('5ac649444f3df45be852df84');
const arr = ['andwived', 'QA Infotech'];
Org.updateMany(
{
name: {$in: arr}
},
{
$pull: {products: productId}
},
callback
);
Related
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
I have a data like below in MongoDB.
const A = { uid: '1234',
works: [
{ name: 'car',
item:['tire','wheel']
},
{ name: 'ship',
item:['tire','wheel']
}
]
My goal is to find whether the name duplicated exists or not.
In conclusion, I want to get only the names.
So 'res.send(result)' gives me like '[car, ship]'.
But the code below doesn't work. How can I make that function? Thank you so much.
const workName = await User.findOne({
uid: userID, works:{$in:['name']}
});
The easy way is to find the aggregate of name and check if the count is greater than one. Since it is inside the the array we need to unwind it.
The below query works, to detect if a sub document contain duplicates for each document.
db.getCollection('collection_name').aggregate([{"$unwind":"$works"} ,{"$group":{"_id":{"name":"$works.name","uid":"$uid"},"count":{"$sum":1}}},{"$match":{"count":{"$gte":2}}}])
if you want to find in all the documents remove uid from _id of group.
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
I need a way to search but not include an _id which is already on the screen in front of the user. For example, I have 3 pet profiles one which the user is already viewing.
On that page I have a heading called My Family. I then run this search:
public function fetch_family($owner)
{
$collection = static::db()->mypet;
$cursor = $collection->find(array('owner' => new MongoId($owner)));
if ($cursor->count() > 0)
{
$family = array();
// iterate through the results
while( $cursor->hasNext() ) {
$family[] = ($cursor->getNext());
}
return $family;
}
}
And it returns all the pets in my family even knowing I am already showing one. So I want to exclude that one _id from the search.
I thought something like this.
$cursor = $collection->find(array('owner' => new MongoId($owner), '$not'=>array('_id'=>new MongoId(INSERT ID HERE))));
However, that just stops the whole thing from running.
You need to do a $ne (not equal) to make sure the current pet you are viewing is excluded from the search by owner.
Example in the mongo shell:
var viewingPetId = ObjectId("515535b6760fe8735f5f6899");
var ownerId = ObjectId("515535ba760fe8735f5f689a");
db.mypet.find(
{
_id: { $ne: viewingPetId },
owner: ownerId
}
)
Use $ne as (notice no need to use ObjectId(), string will autocast to ObjectId):
db.organizations.find({"_id" : {$ne:"563c50e05cdb2be30391e873"}})