Hi,
Below shows my attempt to combine my (fast)method and (slow, but reactive)subscription inside a react container.
It loads the client collection, but when I test the reactivity by removing a doc(line) on the server (using the mongo console) I get the following error on the client:
Uncaught Error: Expected not to find a document already present for an add
//========== Client only code =============
export const Lines2 = new Mongo.Collection('Lines2');
function insertBulk(collection, documents) {
if (collection) {
const last = _.last(documents);
_.each(documents, (item) => {
if (_.isObject(item)) {
// console.log('bulked');
if (false) console.log('false'); //(item._id === last._id) {console.log('a');collection.upsert({ _id: last._id }, item);}
else
if (_.isObject(item._id)) {
const string = item._id.toHexString()
collection._collection._docs._map[string] = item;
} else collection._collection._docs._map[item._id] = item;
}
});
}
}
function composer(props, onData) {
const { modelId } = props;
const publishedLines = {};
Meteor.call('lines2.method', modelId, (err, lines) => {
if (err) throw err;
else {
lines.forEach(line => {
publishedLines[line._id._str] = true;
});
insertBulk(Lines2, lines);
}
});
if (Meteor.subscribe('lines2.bymodelId', modelId, publishedLines).ready()) {
console.log('sub ready');
const lines = Lines2.find().fetch();
onData(null, {
lines: Immutable.fromJS(lines),
});
}
}
export const LinesContainer2 = composeWithTracker(composer, null, null, { withRef: true })(LinesLayer);
//==========Server only code===
function updatePub(self, simplifiedlinks, publishedLines) {
const latestIds = simplifiedlinks.map((link) => link._id._str);
const publishedIds = Object.keys(publishedLines);
_.difference(publishedIds, latestIds).forEach((key) => { // _ needs strings not objectIds
delete publishedLines[key];
self.removed('Lines2', new Mongo.ObjectID(key));
});
simplifiedlinks.forEach((link) => {
if (publishedLines[link._id._str]) {
self.changed('Lines2', link._id, link);
} else {
publishedLines[link._id._str] = true;
if (publishedLines[link._id._str]) {
self.added('Lines2', link._id, link);
}
}
});
}
Meteor.methods({
'lines2.method': function(modelId){
console.log('lines2.method');
check(modelId, Mongo.ObjectID);
const lines = calcLines(modelId, this.userId);
return lines;
},
});
Meteor.publish('lines2.bymodelId', function linesPublication(modelId, publishedLines) {
console.log('lines2.bymodelId');
check(modelId, Mongo.ObjectID);
check(publishedLines, Object);
const self = this;
const model = Models.findOne(modelId);
if (!model) self.ready();
else if (!isMember.bind(self, model.modelId)) self.ready();
else {
// const publishedLines = {};
let initializing = true;
const linksHandle = Links.find({ modelId }).observe({ // update client if the links change
added(newLink) {
if (!initializing) {
console.log('linksHandle added newLink ',newLink)
const simplifiedlinks = calcLines(modelId, self.userId);
updatePub(self, simplifiedlinks, publishedLines);
}
},
changed(newLink, oldLink) {
console.log('linksHandle changed newLink ',newLink,' oldLink',oldLink)
const simplifiedlinks = calcLines(modelId, self.userId);
updatePub(self, simplifiedlinks, publishedLines);
},
removed(oldLink) {
console.log('linksHandle removed oldLink ',oldLink)
const simplifiedlinks = calcLines(modelId, self.userId);
updatePub(self, simplifiedlinks, publishedLines);
},
});
initializing = false;
// const simplifiedlinks = calcLines(modelId, memberId);
// updatePub(self, simplifiedlinks, publishedLines);
self.ready();
self.onStop(() => {
linestylesHandle.stop();
linksHandle.stop();
});
}
});