0

Right now, Mongo is skipping over this update because of a syntax error. And when I try different placements for the $.to. (like replies.$.to), this results: [MongoError: cannot use the part (to of replies.0.to.read.marked) to traverse the element..]

How should the $set be edited:

Models.Message.findOneAndUpdate(

  { "replies._id": ObjectId("53dd4b67f0f23cad267f9d8b"), "replies.to.username": "UserA" },
  {
    "$set": { 
        "$.to.read.marked": true,
        "$.to.read.datetime": req.body.datetimeRead,
        "$.to.updated": req.body.datetimeRead
    }
  },

To $set to.read.marked:true for userA of the specific reply:

{
    "_id" : ObjectId("53daf26af7b70fd82ffd4cff"),
    "updated" : ISODate("2014-08-02T20:36:03.000Z"),
    "message" : "here's a message",
    "replies" : [ 
        {
            "reply" : "here's a reply",
            "created" : 1407011687000,
            "_id" : ObjectId("53dd4b67f0f23cad267f9d8b"),
            "to" : [ 
                {
                    "username" : "userA",
                    "updated" : ISODate("2014-08-02T20:34:47.000Z"),
                    "_id" : ObjectId("53dd4b67f0f23cad267f9d8c"),
                    "read" : {
                        "datetime" : ISODate("2014-08-02T20:34:47.000Z"),
                        "marked" : false
                    }
                },
                {
                    "username" : "userB",
                    "updated" : ISODate("2014-08-02T20:34:47.000Z"),
                    "_id" : ObjectId("53dd4b67f0f23cad267f9d8d"),
                    "read" : {
                        "datetime" : ISODate("2014-08-02T20:34:47.000Z"),
                        "marked" : false
                    }
                }
            ]
        }, 
        {
            "reply" : "here's another reply",
            "created" : 1407011763000,
            "_id" : ObjectId("53dd4bb3a9f9497e270525cb"),
            "to" : [ 
                {
                    "username" : "userA",
                    "updated" : ISODate("2014-08-02T20:36:03.000Z"),
                    "_id" : ObjectId("53dd4bb3a9f9497e270525cc"),
                    "read" : {
                        "datetime" : ISODate("2014-08-02T20:36:03.000Z"),
                        "marked" : false
                    }
                },
                {
                    "username" : "userB",
                    "updated" : ISODate("2014-08-02T20:36:03.000Z"),
                    "_id" : ObjectId("53dd4bb3a9f9497e270525cd"),
                    "read" : {
                        "datetime" : ISODate("2014-08-02T20:36:03.000Z"),
                        "marked" : false
                    }
                }
            ]
        }
    ],
    ...
}
StackThis
  • 883
  • 3
  • 15
  • 45

1 Answers1

1

You can't use $ for nested arrays. So you can't use update at all. Follow this issue.

So you will need to make a find query for replies._id and proceed to get the index/indexes manually.

An ugly option would be to

Models.Message.findOne({ "replies._id":ObjectId("53dd4b67f0f23cad267f9d8b", "replies.to.username": "UserA")},
   function(err,doc){
       if(doc){
       //use a for loop over doc.replies to find the index(index1) of ObjectId("53dd4b67f0f23cad267f9d8b") at replies[index]._id
       var index1;
       for(var i=0;i<doc.replies.length;i++){
          if(doc.replies[i]._id === ObjectId("53dd4b67f0f23cad267f9d8b")){
             index1=i;
             break;
          }
        }
        var index2;
       //use a for loop over doc.replies[index1].to and find the index(index2) of "UserA" at replies[index1].to[index2]
       for(var j=0;j<doc.replies[index1].to.length;j++){
         if(doc.replies[index1].to[index2].username==="UserA"){
            index2=j;
            break;
         }
       } 

       doc.replies[index1].to[index2].read.marked = true;
       doc.replies[index1].to[index2].read.datetime = req.body.datetimeRead;
       doc.replies[index1].to[index2].updated= req.body.datetimeRead;
       doc.markModified('replies')
       doc.save(function(err,doc2){...})
     }
   });
ma08
  • 3,654
  • 3
  • 23
  • 36
  • Wow. Alright..thanks for the heads up. Are there any alternatives for producing the desired result? – StackThis Aug 03 '14 at 00:04
  • If I pass replies.to._id instead of the replies._id could it then be updated? – StackThis Aug 03 '14 at 00:06
  • Still no. Same problem applies - nested arrays. That update will need multiple positional operators too which is not present. Consider redesigning your schema if you need these kind of nested updates frequently. It is theoretically possible but it will involve a lot of overhead. – ma08 Aug 03 '14 at 00:08
  • Hmm.. would the find query that you're speaking of be pseudo-synchronous if encapsulated by an if (something) {repliesIDsArray.forEach(repliesIDsArrayUpdate); ..find query for each replies._id.. } such that the code will continue on only after this if & forEach are done? (node.js) – StackThis Aug 03 '14 at 00:11
  • This is a frequent operation..any suggestions for an alternative schema design? – StackThis Aug 03 '14 at 00:14
  • @StackThis I can't quite understand what you are asking? Please rephrase that. Schema design is associated heavily with the use case which includes readfrequency, writefrequency and query frequency. Lots of factors need to be taken into consideration. Maybe [this is the right place to discuss that](http://dba.stackexchange.com/) – ma08 Aug 03 '14 at 00:19
  • Could you elaborate on what it looks like to proceed to get the index/indexes manually? Thanks – StackThis Aug 03 '14 at 00:22