Removing Non-Collection Embedded Document via Mongo Shell - mongodb

So I've got an application that uses a lot of embedded documents, which is fine. However I've noticed that some embedded documents aren't displayed when you show collections in Mongo shell.
Normally this isn't an issue, but whilst dicking with setting embedded documents, I accidentally added an empty entry to one of the entries. I'd normally do something like this to remove the entry db.collection.remove({_id: ObjectId('<OBJECT_ID>')}), but since some of these aren't actual collections I'm unable to do it like this.
I'm also not sure how I'd splice out this successfully while actually removing the document. I could splice it out of the entry, but I have a feeling it would leave that embedded document floating around somewhere in the DB.
Any ideas how to do this?
To give you an idea what I'm talking about, an example of the entry:
entry = {
_id: ObjectId('blah blah blah'),
name: {
first: 'example',
last: 'city'
},
log : [
{
_id: ObjectId('some id'),
action: 'whatever',
someField: 'etc.'
},
{
_id: ObjectId('another id')
},
{
_id: ObjectId('yet another id'),
action: 'who cares',
someField: 'data'
}
]
}

If you want to remove one of the log entries, then you want the $pull operator.
The format would be something like:
db.collection.update({_id:<id-of-document-to-update>},
{$pull:{"log._id":<id-of-log-entry-to-remove>"}}
)
This says, find document with certain _id and remove from log array an entry with certain sub_id.

Related

what is the proper way to use $nin operator with mongoDB

I want to find entries in my MongoDB collection that match some filters.
Each entry in my mongo collection looks like this data:
{
type: "admin"
senderId: "6131e7c597f50700160703fe"
read_by: [
{
Object_id: 614dbbf83ad51412f16c0757
readerId: "60b968dc5150a20015d6fcae"
}
]
},
{
type: "admin"
senderId: "6131e7c597f50700160703fe"
read_by: [
{}
]
}
What I want to achieve properly, is to filter on the collection and get only the entries that match 'admin' as type and that don't have the current user's ID in the read_by array (that is an array of objects)
I wrote this (and tried some other combinations with errors :) )
but it is not working, I get 0 entries on the end, but I expect to get one of the two as the second have it's read_by array empty.
Thank you very much!
I validated my solution using cloud.mongodb.com interface and the simplest following filter seems to do the job:
{ "read_by.readerId": {$ne:"60b968dc5150a20015d6fcae"}}
Only the record with empty array is being returned.
$nin operator works fine as well but if there is only single value for comparision then $ne should be enough.
{ "read_by.readerId": {$nin: ["60b968dc5150a20015d6fcae"]}}

Mongoose findOneAndUpdate an array within an array within a document

I'm trying to update an array that sits inside another array in a document. The schema is like this:
const projectSchema = new mongoose.Schema({
stakeholders: [{
stakeholderTitle: {
type: String,
},
...
subgroup: [{
subgroupTitle: {
type: String
},
subgroupPercent: {
type: Number,
}
}]
}],
and I'm trying to update the 'subgroup' array. I have got the query to work on its parent (the stakeholder array) with the positional $ operator, using the answer to this question I asked previously. So my query looks like this.....
await db.findOneAndUpdate({ find by the id }, { "stakeholders.$.stakeholderTitle": req.body.stakeholderTitle, ... "stakeholders.$.subgroup": req.body.subgroup })
However, this query doesn't work for the 'stakeholders subgroup' array, and makes it null. Looking through the mongo docs for the positional operator it states that 'The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value', which I guess might be my problem.
So how can I do this with a findOneAndUpdate query?
From what I see is you have to specify the object you want to update inside the subgroup array. Try this - (i.e I'm updating the subgroupTitle of the subgroup array);
await db.findOneAndUpdate(
{
_id: userId,
"stakeholders.stakeholderTitle": req.body.stakeholderTitle,
"stakeholders.stakeholderTitle.subgroup.subgroupTitle": req.body.subgroupTitle
},
{$set: {
"stakeholders.stakeholderTitle.subgroup.$.subgroupPercent": somePercentValue,
}
},
);
Also note, it's only the array that you find that you can update. It might not be exactly what you want, but its a step closer

Mongo Oplog - Extracting Specifics of Updates

Say I have an entry in the inventory collection that looks like
{ _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera" ]}
and I issue the command
db.inventory.update(
{ _id: 1 },
{ $addToSet: { tags: "accessories" } }
)
I have an oplog tailer, and would like to know that, specifically, "accessories" has been added to this document's tags field. As far as I can tell, the oplog always normalizes commands to use $set and $unset to maintain idempotency. In this case, the field of the entry describing the update would show something like
{$set : { tags : ["electronics", "camera", "accessories"] } }
which makes it impossible to know which tags were actually added by this update. Is there anyway to do this? I'm also curious about the analogous case in which fields are modified through deletion, e.g. through $pull. Solutions outside of the realm of an oplog tailer are welcome, as well as pointers to documentation of this command normalization process - I can't find it.
Thanks!

Meteor/Mongo, push into an array inside an object inside an array

I am trying to teach myself Meteor and Mongo. I have a particular insertion inside my Meteor method that is driving me nuts.
My document object looks like this:
{
_id
name: "name",
stuff: {},
array: [
{
id: 0,
target:[
{
id: 0,
name: "1"
},{
id: 1,
name: "2"
}
]
},{
id: 1,
target:[
{
id: 0,
name: "A"
},{
id: 1,
name: "B"
}
]
}
],
}
I am trying to add objects into the target array, which is inside an object inside the array-array.
I have tried a number of different approaches over a few days based on some things I have seen here on stack overflow. The most recent attempt is:
Documents.update({_id: id, 'array.id': arrayId}, {$addToSet:{'array.$.target': objectToInsert}},{upsert: false, multi: false})
If anyone could point me in the right direction I would appreciate it.
I donot know the mongo query to do something like this but it can be done as below
let theArray=Document.findOne({_id:id}).array,
arrayOfIds=_.pluck(theArray,"id"),
index=_.indexOf(arrayOfIds,arrayId),
theArray[index].target.push(objectTobeInserted)
Now update the document with the modified array
Document.update({_id:id},{$set:{array:theArray})
If you donot understand _.pluck and _.indexOf, you can refer to underscorejs
Seems this could be an issue with where you are doing the update. If this is on the client, then see here:
Update an subdocument contained in an array contained in a MongoDB document
Solution is to move this to the server.
Also, you may want to look at the difference between $addToSet and $push here MongoDb: Difference between $push/$addtoset
If this is not on the client side and changing to push does not fix your issue, can you add to your question what the error is.

Update records within arrays

I've just started to look at meteor and I'm stuck trying to update a record within an array within a record. Say i have a document that looks something like this:
Users:
{
_id: "somerandom",
name: "name1",
items, [
{
name: "item1",
data: "somedata",
...
},
{
name: "item2",
data: "somedata",
...
}
],
...
},
...
And I want to update the data of items 'item1'. I can't find anything on how to do this in meteor, but from what I have read about MongoDB I think that the correct way would be something like
Users.update({_id: userId, "items.name": 'item1}, {$set: {"items.$.data": newData}});
but since the MongoDB used in Meteor doesn't support $ it won't work, on the other hand I might be way of how this should be done.
Does anyone have a solution for this?
Use Meteor.methods() and implement your database operation on the server side and call it using Meteor.call() from the client. This feature is not yet implemented in Meteor and it is documented here.
You can read more in the discussion on this issue raised on Github, here.
I found a workaround at meteor's github https://github.com/meteor/meteor/blob/master/examples/parties/model.js
The idea is to first get the index of the array-item you want to change and then use that index instead of $. So in this case it would be something like
user = Users.findOne(userId);
index = _.indexOf(_.pluck(user.items, 'name'), 'item1');
modifier = {$set: {}};
modifier.$set["items." + index + ".data"] = newData;
Users.update(userId, modifier);