Manage stop sync and remove document from Couchbase lite - which is removed from a user's channel

Hope the title does justice to my question.

Using Current Latest stable Couchbase Server (community) and Sync Gateway Mobile (and counter couchbase lite).
Platform: Server Linux Ubuntu and Client - Xamarin Forms (iOS / Android - .NET SDK)

I have a scenario explaining it as follows:
There are three users in system - UserA, UserB, UserC.

I create one document where we add a property of type list for who are part of this document (its a meeting) - so when I create I add UserA (as he is creating this document on his app) and UserB on to the list.

document.properties.participants = [“UserA”, “UserB”].
I have a sync function which then adds this document to “UserA” and “UserB” channel. This works fine as “UserC” cannot see this document and is not synced to his device.

Now the user wants to change participants who can see or work against this document. So “UserA” updates document.properties.participants as follows:

document.properties.participants = [“UserA”, “UserC”]. This work partially where UserC now sync the document and see the same, but UserB should not see that document and the document should be removed from his sync channel and local SQL lite.

Here is my sync function snapshot:

function (doc, oldDoc) {

var docType = "unknown";
if (doc._deleted) {
    docType = oldDoc.type;
}
else {
    docType = doc.type;
}

if (docType == 'meeting') {
    if (oldDoc == null) {
        for(var counter = 0; counter < doc.attendees.length; counter++) {
          access(doc.attendees[counter], "sm-" + doc.attendees[counter]);
          channel("sm-" + doc.attendees[counter]);
        }
    }
    else {
      for(var counter = 0; counter < doc.attendees.length; counter++) {
        access(doc.attendees[counter], "sm-" + doc.attendees[counter]);
        channel("sm-" + doc.attendees[counter]);
      }
    }
  }
}

I tried using database.compact() to see if that helps on client but has not good results. I can still see the document on UserB’s device.

I am using Push / Pull replications with continous as true in my app on all user’s device.

Really seeking helps to get this sorted and spot the mistake I am doing which I can rectify and move on.
Thanks in advance

Your loop looks the same whether oldDoc is null or not.

I think you would need to push the changed document to UserB’s channel based on being an attendee in oldDoc. If you only update based on the new list, UserB won’t see the changes.

Oh yes I agree about the same code for oldDoc is null or not, thanks for pointing out.

Ok the second part:

I think you would need to push the changed document to UserB’s channel based on being an attendee in oldDoc. If you only update based on the new list, UserB won’t see the changes.

I am not able to understand what you mean to say.
Can you please show an sample or a small hint snippet about your suggestion, that would really help, thanks @hod.greeley

Turns out Sync Gateway handles this automatically. When a new revision of a document causes it to no longer match a channel, SG sends a special change notice to the old channel recipients. Couchbase Lite picks up this change notice. The document gets a special tombstone revision with the property _removed:true. The document will no longer show up in queries, and so on.

So, in short, you get the behavior you want automatically just by not sending to UserB’s channel. If this isn’t happening, it’s a bug.

Syncing does take a moment, so be sure the update has propagated fully. You can monitor the changes feed to see that the right update is happening.

You can see a very crude example of how to monitor the changes feed here, in the SGMonitor class: https://github.com/HodGreeley/couchbase-lite-java-sg-replicate

@hod.greeley - I agree with your point. SG handles that with a _removed: true tombestone as we read in the docs and discussed everywhere.

But that did not happened for my app and setup. So not sure if that is a bug or issue with by SG and CB lite configurations. (I am using a view on CB lite to get this data - do i need to destroy that and recreate it?)

I also tried dbinstance.compact() to see if that works but no success.

Also you mentioned in your sample at GH that i can use the http://domain/dbname/_changes to see what is changed and sent back but i cannot use that directly as all users access is authenticated.

Is there something i need to pass in the HTTP request above to “_changes” for the authenticated user request?

One more thing while I have you responsive to my question (I cannot thank you enough for the help) - I am not able to see any logs on server side when i run the sync gateway as : ./sync_gateway mysyncgatewayconfig.json

I have put some logs in the sync function as console.log("log statement"); which does not show up on the terminal.

Thanks in advance

@jsinh You shouldn’t have to change the view. You will still see the tombstone if you get all documents, but a view should filter it.

How you pass authentication credentials depends on how you authenticated. What method are you using?

The logs by default go to stderr. I think the usual sync gateway redirects this, or something. There is a configuration parameter, logFilePath. You can use that to keep logs in a file.

@hod.greeley Thanks for the reply.

Ok now i understand, the issue is not with the views to refresh. But I am pretty sure there is no _removed = true tombstone for UserB.

I am creating user by post to following API

http://my-server:4985/db/_user/

Can you guide on how can i make an authenticated call to _changes (based on above way created users in the system)? Thanks

I do have the logs getting written to file, but for times like this I also or just want the logs to getting displayed on the terminal (stderr as you call it). Any specifics on this configuration change too?

Note that you will not see the _removed entry until it is removed from all channels that the user has access to and the document is in.

Also you can send an authenticated request using HTTP basic auth as a test if you have a user with a password -> http:// {user}:{password}@{server-address}

@borrrden
Ok so that is why it is not getting removed from UserB’s channel because the user is still having access to that channel. The action I take is expected to just remove the document from that channel which UserB has access to.

any workaround to fix it in this case?

http:// {user}:{password}@{server-address} - worked thanks. I will start observing _changes now to get more insights.

@jsinh I think you misunderstood what @borrrden said.

Let’s say UserB has access to two channels, X and Y. To start, the sync function assigns a document to both channels. UserB will get a normal revision.

Next, something changes so that the sync function only assigns the document to channel X. Since UserB has access to channel X, UserB sees the any new revisions. If another change is made so the document is no longer assigned to either X and Y, then the special tombstone revision should be sent to UserB.

So from what you’ve described (action taken to remove document from channel UserB has access to) should trigger the document getting removed. You should check carefully that the document is really not sent to a channel UserB can read. See documentation about troubleshooting channels here for more: http://developer.couchbase.com/documentation/mobile/current/develop/guides/sync-gateway/channels/index.html#inspecting-document-channels