Automattic / mongoose

MongoDB object modeling designed to work in an asynchronous environment.
https://mongoosejs.com
MIT License
26.8k stars 3.81k forks source link

Cannot update existing embedded docs and add new embedded doc in the same parent save() call #920

Closed adrianocola closed 12 years ago

adrianocola commented 12 years ago

Consider the following schema:

     var Comments = new Schema({
        title     : String
        , position      :  Number
    });

    var BlogPost = new Schema({
        author    : String
        , comments  : [Comments]
    });

    var Post = mongoose.model('BlogPost', BlogPost);
    var Comm = mongoose.model('Comments', Comments);

Have this single BlogPost in DB:

   {               
        author: "AuthorName",
        comments: [
            {
                title: "Title X",
                position: 0
            },
            {
                title: "Title Y",
                position: 1
            }
        ]
    }

I want to add a new comment and change the order of the existing ones, so that the new comment is the first one (position 0)

  //found one BlogPost
  BlogPost.findById(id,function(err,bp){

        //increment positions of existing Comments
        var i;
        for(i=0; i < bp.comments.lenght; i++){
            bp.comments[i].position += 1;
             console.log("POSITION: " + bp.comments[i].position ) //prints the position plus 1
        }

        // create a new Comment
        var comment = new Comm({title: "Title Z", position: 0});

        // add new comment to the current BlogPost
        bp.comments.push(comment);

        // try to save the updates and the insertion in the same request
        bp.save(function(err){
            // no err here!
            if(err) return;

            //success!
            res.send("SUCCESS!");
        });

    })

The new commend is added, but all the updates to the existing embedded docs aren't committed! If I remove the line "bp.comments.push(comment);" the embedded docs are updated!

crapthings commented 12 years ago

throw e; // process.nextTick error, or 'error' event on first tick ^ TypeError: Cannot call method 'push' of undefined

yes i can't use push too

my code

var Model = require('../../models/db'),
model = new Model('mindsocial');

module.exports = function(server) {

server.post('/api/nodes/:nodesId', function(req, res) {
    model.nodes.findById(req.params.nodesId, function(failtofindnodes, nodes) {
        if (!failtofindnodes) {
            if (!nodes) {
                res.send(null);
            } else {
                var node = new model.node({
                    title: req.body.title,
                    content: req.body.content
                });
                nodes.nodes.push(node);
                nodes.save();
                res.send(node);
            }
        } else {
            res.send('请求失败。');
        }
    });
});

server.get('/api/nodes/:nodesId', function(req, res) {
    model.nodes.findById(req.params.nodesId, function(failtofindnodes, nodes) {
        if (!failtofindnodes) {
            if (!nodes) {
                res.send(null);
            } else {
                res.send(nodes);
            }
        } else {
            res.send('请求失败。');
        }
    });
});

server.get('/api/nodes', function(req, res) {
    var query = model.nodes.find({});
    query.limit(100).exec(function(failtofindnodes, nodes) {
        if (!failtofindnodes) {
            if (!nodes) {
                res.send('请求的内容不存在。');
            } else {
                res.send(nodes);
            }
        } else {
            res.send('请求失败。');
        }
    });
});

};
aheckmann commented 12 years ago

@ adrianocola yes this is a problem on 2.x. can you try this on master? It should be working there.

adrianocola commented 12 years ago

Confirmed, it's working on master!

Thank you for the support and thank you very much for this great library!

aheckmann commented 12 years ago

:)

On May 19, 2012, at 6:48 PM, adrianocolareply@reply.github.com wrote:

Confirmed, it's working on master!

Thank you for the support and thank you very much for this great library!


Reply to this email directly or view it on GitHub: https://github.com/LearnBoost/mongoose/issues/920#issuecomment-5805000

athingisathing commented 11 years ago

So.......Per @CrapThings (Seriously ;))....

I have tried sooooooo many things including RC0 3.0 but i still can not fill a model from arrays. (embed)

Mind you this is not all the code...

I have tried This:

  things.find({ tName: /Fujifilm/i }, function foundThings(err, items) {
        var features = mongoose.model('features');
        var featureslist = new features;
        items.forEach(function(th,featureslist) {
            featureslist.push(th.Features);
        });

This: things.find({ tName: /Fujifilm/i }, function foundThings(err, items) { // var features = mongoose.model('features'); var featureslist = new features; items.forEach(function(th,featureslist) { featureslist.push(th.Features); });

And this works... kind of... but its not a mongoose model...

  things.find({ tName: /Fujifilm/i }, function foundThings(err, items) {
       // var features = mongoose.model('features');
        var featureslist = [];
        items.forEach(function(th,featureslist) {
            featureslist.push(th.Features);
        });

I want to fill a model with an existing document. CLone a model.. merge two models of like objects... but maintain the mongoose model.

when i try to push into a model from an existing model i get the same error as @crapthings "TypeError: Cannot call method 'push' of undefined"

i also have tried these dif ways:

featureslis.array.push(th.Features); featureslist.schema.push(th.Features); featureslist...xxxxx......push(th.Features);

please help!!! ;)

aheckmann commented 11 years ago
things.find({ tName: /Fujifilm/i }, function foundThings(err, items) {

in this case, items is an array of "filled" mongoose documents.

var features = mongoose.model('features');
var featureslist = new features;

here, featurelist is a single object, not an array. think of a document as the object literal you see in the mongo shell when querying for a single document.

http://mongoosejs.com/

athingisathing commented 11 years ago

Soooo......THANKS

I am new to node.js and mongo and I come from a .net background. This is what i ended up with. I guess what I was missing was that after the find its really just and array of object. not a mongoose "thing"...

        var features = [];
        items.forEach(function(th) {
            th.Features.forEach(function(f) {
                features.push(f);
            });
        });
        res.render('index', { title: 'My Things List 2', features: features })

This worked.

aheckmann commented 11 years ago

yep. glad you got it! i used to do .net a long time ago as well. i found node refreshingly straightforward.