MongoDB: Updating a document in an array - mongodb

I have a collection with documents of this schema:
{
_id: something,
recipients: [{id:1, name:"Andrey", isread:false}, {id:2, name:"John", isread:false}]
}
Now, I want to update "isread" for John (id = 2) using findAndModify(), because I also need to get the original document.
I'm trying this command:
db.messages.findAndModify({query:{'recipients.id':2}, update:{'recipients.$.isread':true}})
but what it does, it just replaces the whole "recipients" field with 'recipients.$.isread', so the document now looks like:
{
_id: someid,
'recipients.$.isread':true
}
What am I doing wrong?

Try to use $set like this:
db.messages.findAndModify({query:{'recipients.id':2}, update:{$set:{'recipients.$.isread':true}}})

Related

Mongodb: findOne by ObjectId inside an array of documents

Sorry for the confusing title, I'm having a hard time describing it.
Basically, here is the document I have stored in my database:
_id: 5fcf596a27365fb14d938afa
vatid:"BE00000011"
name:"ACME Inc"
users: [ {
_id: 5fcf596a27365fb14d938afb,
id: 5fcf596a27365fb14d938af9,
role:"admin"
}
]
Id like to find the object that contains this id: 5fcf596a27365fb14d938af9 inside the users array.
What would the query look like?
Thanks!
This should do the thing:
{"users.id" : "5fcf596a27365fb14d938af9"}

MongoDB - how to only update field if field does not exist

How can I update a mongo document with the following requirements:
Find a document by email property:
If the document exists:
If both retrieved and new document have property A, keep property A (the retrieved one).
If retrieved document property A is null or undefined or doesn't exist, update using property A of the new object.
If the document doesn't exist
Insert the new document.
The findOneAndUpdate seems not to convey the both 3 of the requirements. Thanks.
My recommendation is to go the following path:
db.getCollection('<some-collection>').update(
{ email: 'someguy#email.com' },
{
$set: {
name: "some guy",
username: someguy,
tel: '1234'
}
},
{ upsert: true }
);
Check upsert documentation:
https://docs.mongodb.com/manual/reference/method/db.collection.update/#upsert-option
Lets go through your requirements now:
3. If the document doesn't exist, insert the new document.
Yes, it will insert new document to collection if it doesnt find the document by email. Resulting document will be combination of find condition + $set + autogenerated _id, so it will look something like this:
{
_id: ObjectId(...)
email: 'someguy#email.com'
name: "some guy",
username: someguy,
tel: '1234'
}
2. If retrieved document property A is null or undefined or doesn't exist, update using property A of the new object.
All properties provided in $set will unconditionally be persisted in the database, which also covers your requirement of updating null/undefined values
3. If both retrieved and new document have property A, keep property A (the retrieved one).
If both newly provided A and database A are the same, we dont have a problem.
If As are different, dont you want to store the new A value?
If you are afraid of nulls/undefined values, you can omit them before providing object to $set.
What is the use-case for you not wanting to update database property with newly provided value?
One use-case i can see is that you want to pass createdAt in case you are creating new record, but dont want to update that value for existing records.
If thats the case, and you know those properties in advance, you can use $setOnInsert update operator. https://docs.mongodb.com/manual/reference/operator/update/#id1
So your update query can look like this:
db.getCollection('<some-collection>').update(
{ email: 'someguy#email.com' },
{
$set: {
name: "some guy",
username: someguy,
tel: '1234'
},
$setOnInsert: {
createdAt: new Date(),
updatedAt: new Date()
}
},
{ upsert: true }
);
I hope this helps!
You need not retrieve the document for updating the property A. You can use the update API of mongo to do so. Please find the psuedo code below:
db.<collection>.update({
"$or": [
{ "PropertyA": { "$exists": false } },
{ "PropertyA": null }
]
}, {$set: {"PropertyA": "NewValue"}});
The above code is for one property, but I think you can figure out how to scale it up.
Hope this helps !!

Finding all records containing any kind of subfield in mongodb

I have a question similar to Finding all records containing a given subfield in mongodb, but where you don't know the subfield name.
Given the following documents:
// Document 1
{
age: 10,
name: "andrew",
meta: {
meta1: true
}
}
and
// Document 2
{
age: 10,
name: "andrew",
meta:{
}
}
I want a query that will find documents that have a value defined for any property inside the meta field. In this case, such a query would only match Document 1.
I tried the following:
db.col.find({ meta: { $ne: "" } })
But it matched all documents including ones where meta had no subfields.
I only want documents with something inside meta.
I've been struggling searching and trying, but nothing.
Thanks
It's simply:
db.col.find({meta: {$ne:{}}})
You were very close!

Query mongo document to return all rows in a field

For example, if I have a name field in mongo document person. In SQL, the query would be like select name from person; to return all names.
What is the equivalent in mongo?
I was thinking db.person.find(<<What do I fill here>>, {name: 1});
I was trying to retrieve all names while using mongo console.
An empty JSON object {} matches all documents.
db.person.find({}, {name: 1});
For correct syntaxe use best practices of mongoDB.
db.person.find(
{ },
{ name: 1, lastname: 1, _id: 0 }
)
In this exemple it shows only "name" and "lastname".

Update meteor collection without removing or overriding existing fields

I don't know why but if i try to update an existing field using the $set method, any existing fields are replaced in the same context.
For example. Say i have an existing collection with the following fields.
Name of collection: Ticket
{profile: {name: "Test", placement: 1}, requestor: _id}
When i attempt to add/update fields to this collection like this:
var ticket = Meteor.tickets.findOne({_id: ticketID});
if(ticket){
Meteor.users.update(ticket, {
$set: profile: {name: "Test2", new_fields: "value"}
});
}
The collection gets updated and the name field changes but placement is removed and no longer there. This is also true if i remove the name field. How do we properly update a meteor collection without having to keep passing the same structure over and over?
Just do this:
$set: {"profile.name": "Test2", "profile.new_fields": "value"}
I.e. You were replacing the whole hash. Instead you can update the fields within the hash.
if the field you want to change have a unique index, you can modify that particular field to what you want without destroying the remaining information in the field.
db.artists.find()
{"_id":ObjectId("1"),"name":"A1","media_id":["m1","m2" ]}
{"_id":ObjectId("2"),"name":"A2","media_id":["m2","m3"]}
{"_id":ObjectId("3"),"name":"A3","media_id":["m3","m1","m2"]}
db.artists.ensureIndex({"name":1})
db.artists.update(
{name:"A1"},
{$set: { name:"A4"}},
{ upsert: true }
)
b.artists.find()
{"_id":ObjectId("1"),"name":"A4","media_id":["m1","m2" ]}
{"_id":ObjectId("2"),"name":"A2","media_id":["m2","m3"]}
{"_id":ObjectId("3"),"name":"A3","media_id":["m3","m1","m2"]}
I am myself quite new in MongoDB but this worked pretty well for me.