Nested documents and _id indexes in mongodb - mongodb

I have a collection with nested documents in it. Each document also has an _id field.
Here's an example of a documents structure
{
"_id": ObjectId("top_level_doc"),
"title": "Cadernos",
"parent": "4fd55bbc5d1709793b000008",
"criterias": {
"0": {
"_id": ObjectId("a_nested_doc"),
"value": "caderno",
"operator": "contains",
"field": "design0"
}
}
}
I want to be able to find the nested document just by searching it's _id
With this query
{
"criterias._id" : ObjectId("a_nested_doc")
}
It returns the parent document (i just want the one that's nested).
Ideally I would do this
{
"_id" : ObjectId("a_nested_doc")
}
And it would return the document with that id (either its nested or not).
Ps. I edited the "_id" values for the sake of simplicity just for this example.

You may have to live with selecting criterias._id (without writing a wrapper around the query, at least), but you can select the document itself by simply retrieving a subset of the fields.
http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields
// The simplest case converted to your use case
db.collection.find( { criterias._id : ObjectId("a_nested_doc") }, { criterias : 1 } );

Related

Delete an array element inside a document with mongoose

I'm not sure if Ihave to get the document ,change the object an d update it on the database or if I can update the document on one step
on this document:
{
"_id":{"$oid":"5fb15c68daa5c11cf5d6d4b3"},"state":[],
"users":[
{"_id":{"$oid":"5fb15c68daa5c11cf5d6d4b4"},"user":{"$oid":"5f81eb91d537dc3baf443a84"},"calification":0},
{"_id":{"$oid":"5fb15c9cdaa5c11cf5d6d4b5"},"user":{"$oid":"5fa6f98f15e96c1125b905a9"},"calification":0}
],
"test":{"$oid":"5f986af2baa88b2d30760961"},
"__v":1}
I know the document id and the users array element id, its possible to delete it in one query?
UPDATE:
I'm using , this code but nothing its done
Game.update({
"_id": req.body.game_id,
},
{
"$pull": {
"users": {
"user": '5f81eb91d537dc3baf443a84'
}
}
})
Yes, you can do in one query.
If I've not missunderstood the question, you only need this:
db.collection.update({
"_id": document_id,
},
{
"$pull": {
"users": {
"_id": user_id_to_remove
}
}
})
You look for the document and then $pull the element which has _id 1 (or whatever you want).
Example here
Note that you can use user field if you want instead of _id.

How do I update a field in a sub-document array with a field from the document in MongoDB?

I have a large amount of data (~160M items) where a date value wasn't populated on the sub-document array fields, but was populated on the parent document. I'm very new to MongoDB and having trouble figuring out how to $set the field to match. Here's a sample of the data:
{
"_id": "5f11d4c48663f32e940696ed",
"Widgets":[{
"WidgetId":663,
"Name":"Super Widget 2.0",
"Created":null,
"LastUpdated":null
}],
"Status":3,
"LastUpdated":null,
"Created": "2018-11-09T18:22:16.000Z"
}
}
My knowledge of MongoDB is pretty limited but here's the basic aggregation I have created for part of the pipeline and where I'm struggling:
db.sample.aggregate(
[
{
"$match" : {
"Donors.$.Created" : {
"$exists" : true
}
}
},
{
"$match" : {
"Widgets.$.Created" : null
}
},
{
"$set" : {
"Widgets.$.Created" : "Created" // <- This is where I can't figure out how to define the reference to the parent "Created" field
}
}
]
);
The desired output would be:
{
"_id": "5f11d4c48663f32e940696ed",
"Widgets":[{
"WidgetId":663,
"Name":"Super Widget 2.0",
"Created":"2018-11-09T18:22:16.000Z",
"LastUpdated":null
}],
"Status":3,
"LastUpdated":null,
"Created": "2018-11-09T18:22:16.000Z"
}
}
Thanks for any assitance
Are you attempting to add the Created field to sub documents on query/aggregation? Or are you attempting to update/save the Created field on the subdocuments?
The $ is an update operator, to be used with updateMany or updateOne. Not aggregate.
https://docs.mongodb.com/manual/reference/operator/query-array/
https://docs.mongodb.com/manual/reference/operator/update-array/
If you just want to add the parents Created field to all subdocuments on query/aggregation this is all you have to do: https://mongoplayground.net/p/yHDHULCSTIz
db.collection.aggregate([
{
"$addFields": {
"Widgets.Created": "$Created"
}
}
])
If your attempting to save the parents Created field to all subdocuments:
db.sample.updateMany({"Widgets.Created" : null}, [{$set: {"Widgets.Created" : "$Created"}}])
Note: This matches any doc that has a subdocument with a null Created field and updates all the subdocuments.

How to make a cloudant query to find documents which two fields are equal

I need to get all documents whose e.g. "_id" field equal to another document field, e.g. "appId"
{
"_id": "xxxx-xxxx-xxxx-xxxx",
"_rev": "xxxx-xxxx-xxxx-xxxx",
"header": {
"appId": "xxxx-xxxx-xxxx-xxxx"
So what would be the query?
"selector": {
"_id": {
"$eq": header.appId
}
},
You can't do "sub queries" with Mango.
From what I see, you're trying to get all the documents listed by appId.
This could be done by using a view.
Your map function would be the following:
if(doc.header && doc.header.appId){
emit(doc.doc.header.appId,{_id: doc.header.appId});
}
The result would be a list of documents mapped by doc.header.appId.
If you query the view with ?include_docs=true, the documents would be joined to the response since we're doing a ManyToJoin join.

Projecting nested documents in Mongo

I am trying to find and project from a nested structure. For example, I have the following document where each unit might have an embedded sub-unit:
{
"_id" : 1,
"unit" : {
"_id" : 2,
"unit" : {
"_id" : 3,
"unit" : {
"_id" : 4
}
}
}
}
And I want to get the id's of all the subunits under unit 1:
[{_id:2}, {_id:3}, {_id:4}]
$graphlookup does not seem to handle this kind of nested structure. As far as I understand, it works when the units are saved at a single level without nesting and each keep a reference to its parent unit.
What is the correct way to retrieve the desired result?
Firstly, $graphlookup isn't operator for your problem, because it's recursive search on a collection, not recursive in a document
$graphLookup Performs a recursive search on a collection, with options
for restricting the search by recursion depth and query filter.
Therefore, it didn't recursive search in your document, it only recursive search on a collection (includes multiple documents), it cannot handle your problem.
With your problem, I think it is not responsibility of Mongo, because you've retrieved your wanted document. You want to parse the retrieved document to array of sub-documents, you can do it in your language.
Example if you use JavaScript (Node.JS for backend), you can parse this document to array:
const a = {
"_id": 1,
"unit": {
"_id": 2,
"unit": {
"_id": 3,
"unit": {
"_id": 4
}
}
}
}
const parse = o => {
const { _id } = o;
if (!o.unit) return [{ _id }];
return [{ _id }, ...parse(o.unit) ];
}
console.log(parse(a.unit));
You can not do that from mongodb query. Mongodb will guarantee the document with id :1, and will not recursively search inside the document.
What you can do is: retrieve the document from mongodb, then parse it into a Map object and retrieve the information from that map, recursively.

How is findById() + save() different from update() in MongoDB

While trying to update a MongoDB document using Mongoose, can I use a findById() with a save() in the callback, or should I stick with traditional update methods such as findByIdAndModify, findOneAndModify, update(), etc.? Say I want to update the name field of the following document (please see a more elaborate example in the edit at the end, which motivated my question):
{
"_id": ObjectId("123"),
"name": "Development"
}
(Mongoose model name for the collection is Category)
I could do this:
Category.update({ "_id" : "123" }, { "name" : "Software Development" }, { new: true })
or I could do this:
Category.findById("123", function(err, category) {
if (err) throw err;
category.name = "Software Development";
category.save();
});
For more elaborate examples, it feels easier to manipulate a JavaScript object that can simply be saved, as opposed to devising a relatively complex update document for the .update() operation. Am I missing something fundamentally important?
Edited 7/21/2016 Responding to the comment from #Cameron, I think a better example is warranted:
{
"_id": ObjectId("123"),
"roles": [{
"roleId": ObjectId("1234"),
"name": "Leader"
}, {
"roleId": ObjectId("1235"),
"name": "Moderator"
}, {
"roleId": ObjectId("1236"),
"name": "Arbitrator"
}]
}
What I am trying to do is remove some roles as well as add some roles in the roles array of sub-documents in a single operation. To add role sub-documents, $push can be used and to remove role sub-documents, $pull is used. But if I did something like this:
Person.update({
"_id": "123"
}, {
$pull : {
"roles" : {
"roleId" : {
$in : [ "1235", "1236" ]
}
}
},
$push : {
"roles" : {
$each: [{
"roleId" : ObjectId("1237"),
"name" : "Developer"
}]
}
}
}
When I try to execute this, I get the error Cannot update 'roles' and 'roles' at the same time, of course. That's when I felt it is easier to find a document, manipulate it any way I want and then save it. In that scenario, I don't know if there is really any other choice for updating the document.
I typically like to use findById() when I am performing more elaborate updates and don't think you are missing anything fundamentally important.
However one method to be aware of in mongoose is findByIdAndUpdate(), this issues a mongodb findAndModify update command and would allow you to perform your first example with the following code: Category.findByIdAndUpdate("123", function(err, savedDoc) {...}).