Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update property in nested array of entities in MongoDB

Is there a straight forward way to update nested array of entities in MongoDB. I am using MongoDB C# Driver for making the DB call from application. Below is an exmaple : say I have a Student collection where each document has a nested array of Course with some necessary fields populated and Course by itself is a separate collection like:

{
 "_id": "234dssfcv456",
 "Name": "Jean Douglas",
 "Age": 32,
 "Courses": 
  [
    {
       "_id": "1234",
       "Name": "Computer Science",
       "Level": "Basic" 
    },
    {
       "_id": "3456",
       "Name": "Bio Science",
       "Level": "Intermediate" 
    }
  ] 
}

I know I can update the nested entity by index something like below but I don't know the index and rather know only the nested Course object Id only.

db.College.Student.update(
    {"Student._id": "234dssfcv456"}, 
    {$set: {
        "Student.$.Courses.1.Level": "Basic"
    }}

Right now, am reading the entire nested array of courses -> doing the modification at application end -> then passing the entire array for update with the filedname "Courses" which is going to replace the existing array with the one passed.

But was thinking, is there an way I can update one entity in array with the Id available. Please suggest.

*** On the right side in Related question section all shows updating the nested array of objects using the index of the object item which is not a possibility for me.

like image 547
Rahul Avatar asked Aug 08 '16 22:08

Rahul


People also ask

How do I update a nested array in MongoDB?

Update Nested Arrays in Conjunction with $[]The $[<identifier>] filtered positional operator, in conjunction with the $[] all positional operator, can be used to update nested arrays. The following updates the values that are greater than or equal to 8 in the nested grades.

How do you update an array of objects in MongoDB?

To perform an update on all embedded array elements of each document that matches your query, use the filtered positional operator $[<identifier>] . The filtered positional operator $[<identifier>] specifies the matching array elements in the update document.

How do I append to an array in MongoDB?

If the value is an array, $push appends the whole array as a single element. To add each element of the value separately, use the $each modifier with $push .

What is addToSet in MongoDB?

The $addToSet operator adds a value to an array unless the value is already present, in which case $addToSet does nothing to that array. The $addToSet operator has the form: { $addToSet: { <field1>: <value1>, ... } } To specify a <field> in an embedded document or in an array, use dot notation.


1 Answers

Mongo shell:

> db.students.find( {_id:"234dssfcv456", "Courses._id":"1234"} ).pretty()
> db.students.update( {_id:"234dssfcv456", "Courses._id":"3456"}, { $set: { "Courses.$.Level" : "Updated" } } )

C# Mongo schema:

public class Student {
  [BsonId]
  [BsonRepresentation(BsonType.String)]
  public string Id { get; set; }
  public string Name { get; set; }
  public int Age { get; set; }
  public Course[] Courses { get; set; }
}

public class Course {
  [BsonId]
  [BsonRepresentation(BsonType.String)]
  public string Id { get; set; }
  public string Name { get; set; }
  public string Level { get; set; }
}

Lookup Mongo docs for the positional operator. With driver higher than version 2.2.3.3 I am using:

  var _client = new MongoClient(@"....");
  var _database = _client.GetDatabase("...");
  var _students =  _database.GetCollection<Student>("students");

  var filter = Builders<Student>.Filter;
  var studentIdAndCourseIdFilter = filter.And(
    filter.Eq(x => x.Id, "234dssfcv456"),
    filter.ElemMatch(x => x.Courses, c => c.Id == "1234") );
   // find student with id and course id
   var student = _students.Find(studentIdAndCourseIdFilter).SingleOrDefault();

  // update with positional operator
  var update = Builders<Student>.Update;      
  var courseLevelSetter = update.Set("Courses.$.Level", "Updated Level");
  _students.UpdateOne(studentIdAndCourseIdFilter, courseLevelSetter);
like image 54
andrei.ciprian Avatar answered Oct 07 '22 01:10

andrei.ciprian