I have a collection which contains several arrays, i.e.
memos: [...]
todos: [...]
I insert each document from an array into a local collection on the client:
if (Meteor.isClient) {
this.Memos = new Mongo.Collection(null);
var results;
results = Projects.findOne({
_id: currentProject_id
});
results.memos.forEach(function(memo) {
return Memos.insert(memo);
});
}
If I call a method to change a memo in the server collection:
({
completeMemo: function(project_id, memo_id, ifCompleted) {
return Projects.update({
_id: project_id,
'memo._id': memo_id
}, {
$set: {
'memos.$.completed': ifCompleted
}
});
}
});
Meteor tries to re-insert the changed document into the local collection, throwing this error:
Exception from Tracker recompute function:
MinimongoError: Duplicate _id '43ttergerg33t3t'
Instead of re-inserting the document, I just want the changes to be reflected.
I've tried modifying return Memos.insert(memo)
to:
Memos.upsert({
_id: memo._id
}, {
$set: {
direction: memo.direction,
sender: memo.sender,
sender_id: memo.sender_id,
sentAt: memo.sentAt,
text: memo.text,
type: memo.type,
viewed: memo.viewed
}
});
However this throws the same error. UPDATE the above works perfectly, the error was from something else. See my answer below.
How can I observe changes on these documents and just update the fields that have changed?
I think I need something like the following:
Memos = new Mongo.Collection;
query = Projects.findOne({
_id: currentProject_id
});
handle = query.memos.observeChanges({
added: function(id, doc) {
Memos.insert(doc);
},
changed: function(id, doc) {
..........???;
},
removed: function(id) {
Memos.remove({
_id: id
});
}
});
Solution:
insert
to upsert
to prevent meteor from trying to insert a new document with the same _id
results.memos.forEach(function(memo) {
return Memos.upsert({
_id: memo._id
}, {
$set: {
direction: memo.direction,
sender: memo.sender,
sender_id: memo.sender_id,
sentAt: memo.sentAt,
text: memo.text,
type: memo.type,
viewed: memo.viewed
}
});
});