Adding a new subfield to a field of all documents in MongoDB - mongodb

{
"_id":{"$oid":"5d6eb64a2a33670cfe44813f"},
"customer":"ddd",
"owners": { "a":"nnn", "b":"mmm"},
}
I have multiple documents in my MongoDB collection that look like above.
I want to be able to add a new field inside the owners to all documents.
For example, if I want to add "c" to the owners of all documents, how can I do that?
I found a query that does something like this:
db.myCollection.update({}, {$set: {"isOpen": false}}, false, true)
But I can I add a new sub-field ("c") to one of the fields ("owners") of my document?
Also tried,
db.profiles.update_many({}, { '$set': {'owners': {'c': ''}}})
but this removes the existing subfields and adds itself.

You are almost there. Just need to add the parent to the $set:
db.profiles.update_many({},{$set: {"owners.c": "something"}});

I guess you should remove $set, set overwrites an existing document

Related

Push values in Mongo Nested Array

enter image description here
Let's say that we have many documents like this in the photo
I have the above schema. I want to find the document based on _id first and then push an array of values to providedServices which belongs to the _id which is inside barbers array
A little help. Can't seem to find this out!
You need to find the related arrays firstly. For this, you can use $elemMatch or write it as 'barbers._id' : {$elemMatch: parameter}' .
Here we tried to find document with filtering it's own id and barbers id. You can change the filter as you wished. It can be only search on barbers id.
Need to write your DocumentName and your parameters instead of idValue, barbersId, serviceModel.
const result = await DocumentName.findOneAndUpdate(
{
$and:
[
{_id: mongoose.Types.ObjectId(idValue)},
{'barbers': {$elemMatch: {_id: mongoose.Types.ObjectId(barbersId)}}}
]
},
{ $push: { 'barbers.$.providedServices': serviceModel } },
{ new: true })
At first, we found the related barbers array inside of all documents. Then we pushed the model inside of providedServices array into this barbers array.

Delete documents from collection based on condition

I want to delete the documents from a collection(Collection1) which are not matching with other collection(Collection2).
collection1 document - {_id: <autogen>, items: [{key:'key', ...}}]
collection2 document - {_id: 'key', action: {key1:'key1', ...}}, {_id: 'non_matching_key', action: {key1:'key1', ...}}
Delete all the documents from collection2, where items.key in collection1 is not matching with _id in collection2. with reference to the above example, a document with key-value 'non_matching_key' should be delete from collection2. There would be similar documents in collection2 like the one with _id value 'non_matching_key'.
The approach I thought was for mark and sweep.
I will add the column in collection2 documents for matching ids(in collection2 with items.key in collection1). This is mark step
Delete all the documents from collection2 where newly added column do not exists. This is sweep step.
Could you please advise if there is a better way of doing this?
Thanks,
Not fully clear how your documents look like and what are the exact conditions, but you could do it like this:
var ids = db.collection1.find({}, { "item.key": 1 }).toArray();
db.collection2.deleteMany({ _id: { $nin: ids } });
So basically, you want to iterate over your collection 2 and get all the ids that are not in collection 1 and delete those or vice versa.
db.collection2.find({}).forEach((doc) => db.collection1.deleteOne({_id: {$ne: doc._id}}))
or
let idsToDelete = db.collection2.find({}).distinct('_id')
let deleteResponse = db.collection1.deleteMany({_id: {$nin: idsToDelete}})
SWAP the collection name in the case of the other way.
NOTE: The code is just to give an overview and is not tested.

How to not list all fields one by one in project when aggregating?

I am using Mongo 3.2.14
I have a mongo collection that looks like this:
{
'_id':...
'field1':...
'field2':...
'field3':...
etc...
}
I want to aggregate this way:
db.collection.aggregate{
'$match':{},
'$project':{
'field1':1,
'field2':1,
'field3':1,
etc...(all fields)
}
}
Is there a way to include all fields in the project without listing each field one by one ? (I have around 30 fields, and growing...)
I have found info on this here:
MongoDB $project: Retain previous pipeline fields
Include all existing fields and add new fields to document
how to not write every field one by one in project
However, I'm using mongo 3.2.14 and I don't need to create a new field, so, I think I cannot use $addFields. But, if I could, can someone show me how to use it?
Basically, if you want all attributes of your documents to be passed to the next pipeline you can skip the $project pipeline. but if you want all the attributes except the "_id" value then you can pass
{ $project: { _id: 0 } }
which will return every value except the _id.
And if by any chance you have embedded lists or nests that you want to flatten, you can use the $unwind pipeline
you can use $replaceRoot
db.collection.aggregate{
"$match": {},
"$project": {
"document": "$$ROOT"
},
{
"$replaceRoot": { "newRoot": "$document" }
}
this way you can get the exact document returned with all the fields in the document...you don't need to add each field one by one in the $project...try using $replaceRoot at the end of the pipeline.

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.

Mongodb find wrong document

You can see my document as bellow. How can I write a find for my uniq fields?
I need search a document where KEYMAP is (SNUM="3151" and "SKEY"="THR" and "SID"="ID_HUT")
{
"CID":"2",
"DESCRIPTION":"test",
"SECKEY":"test",
"API":{
"SMS":"http://api.php",
"DR":"http://api2.php"
},
"LOGS":{
"IN":"log_cid_in_1",
"OUT": "log_cid_out_1"
},
"KEYMAP":[
{"SNUM":"3151","SKEY":"THR", "SID":"ID_HUT"},
{"SNUM":"3152","SKEY":"ONE", "SID":"ID_XL"},
{"SNUM":"3153","SKEY":"TWO", "SID":"ID_INDO"}
]
}
db.content_provider_map.ensureIndex({"KEYMAP.SNUM":1,"KEYMAP.SKEY":1,"KEYMAP.SID":1},{unique:true});
db.mycollection.find({"KEYMAP.SNUM":"3151","KEYMAP.SKEY":"TWO","KEYMAP.SID":"ID_XL"});# not work. it find the document
I believe you want to use $elemMatch ( http://docs.mongodb.org/manual/reference/operators/#_S_elemMatch ) here like:
find({KEYMAP: {$elemMatch: {SNUM: "3151", SKEY: "TWO", SID: "ID_XL"}}})
Also unique indexes on subdocuments do not work the way you probably think they do. They create uniqueness across all documents not just that one document. If you want a unique index on that one document then you will need to use something like $addToSet or an upsert function on the subdocument.