Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removing docs in a linked collection leads to <linkedId>: null in another linked collection #450

Open
Twisterking opened this issue May 7, 2021 · 1 comment

Comments

@Twisterking
Copy link

Twisterking commented May 7, 2021

Hello @theodorDiaconu !

You might remember me as the "bit annoying guy with way too many Grapher questions" some months/years ago! 😁

So I have been using grapher in production successfully for many years now and still am very happy.

For months I have had the problem that in some collections more and more documents popped up with <linkedCollId>: null, rendering them simply unuseable.

I have the following case:

I have 2 collections: items and prices.

items Links:

Items.addLinks({
  prices: {
    collection: Prices,
    inversedBy: 'item'
  }
});

prices links:

Prices.addLinks({
  item: {
    type: 'one',
    collection: Items,
    field: 'itemId'
  }
});

In one of the most important functions of my app, I sometimes have to delete many items documents. At some point in this function I have an array with itemIds which should be deleted.

if (toBeRemovedIds && toBeRemovedIds.length > 0) {

  // ALWAYS remove the pricedata
  let removePricesQuery = Object.assign({ itemId: { $in: toBeRemovedIds } }, priceFindAssign);
  try {
    const removedNum = await Prices.remove(removePricesQuery);
    if (removedNum) result.PricesRemoveResult = { ok: true, removed: removedNum };
  } catch (err) {
    console.error('Prices.remove ERROR:', err);
  }

  // Actually remove the items
  try {
    const removedNum = await Items.remove({ _id: { $in: toBeRemovedIds } });
    if (removedNum) {
      result.ItemsRemoveResult = { ok: true, removed: removedNum, removedItemRefs };
    }
  } catch (err) {
    console.error('Items.remove ERROR:', err);
  }

}

So I FIRST deleted the linked prices, THEN I delete the items themselves.

This does NOT SEEM TO WORK. The above code results in many documents in the prices collection with itemId: null!

I really need some input here. This is just an example, ALL of my linked collections are full of documents with<myLinkedIdHere>: null.

Any input is appreciated!

Cheers, Patrick

@Prinzhorn
Copy link

Prinzhorn commented Aug 25, 2021

What is priceFindAssign? If this limits the set of updates on Prices you will run Items.remove with more ids than Prices.remove. This means you leave Prices in your database that were in toBeRemovedIds. But then you remove all Items that match toBeRemovedIds and boom grapher sets Prices.itemId it to null for Prices that were originally in toBeRemovedIds and excluded due to priceFindAssign.

grapher/lib/links/linker.js

Lines 288 to 320 in 842dbb1

_handleReferenceRemovalForVirtualLinks() {
this.mainCollection.after.remove((userId, doc) => {
// this problem may occur when you do a .remove() before Meteor.startup()
if (!this.linkConfig.relatedLinker) {
console.warn(
`There was an error finding the link for removal for collection: "${
this.mainCollection._name
}" with link: "${
this.linkName
}". This may occur when you do a .remove() before Meteor.startup()`
);
return;
}
const accessor = this.createLink(doc);
_.each(accessor.fetchAsArray(), linkedObj => {
const { relatedLinker } = this.linkConfig;
// We do this check, to avoid self-referencing hell when defining virtual links
// Virtual links if not found "compile-time", we will try again to reprocess them on Meteor.startup
// if a removal happens before Meteor.startup this may fail
if (relatedLinker) {
let link = relatedLinker.createLink(linkedObj);
if (relatedLinker.isSingle()) {
link.unset();
} else {
link.remove(doc);
}
}
});
});
}

unset() {
if (this.isVirtual) {
this._virtualAction('unset', what);
return this;
}
let field = this.linkStorageField;
this.object[field] = null;
this.linker.mainCollection.update(this.object._id, {
$set: {
[field]: null
}
});
return this;
}

You could use autoremove and only remove Items.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants