How to remove doc for all channels

I’d like to remove a document from all clients. I tried simply not calling the channel() function in my sync-function but the removed revision is still appearing in my client changes feed, and not with a removed flag - just a regular change.

According to the docs after removing a document from a channel I should see a "\_removed":true property (but it doesn’t say where… on the document perhaps?). It also doesn’t say how you remove a doc from a channel, I assume by just not calling the channel() function in my sync function?

And these docs say that “A document can be removed from a channel without being deleted” - which is exactly what I’m trying to achieve. It goes on to say that _"Sync Gateway’s changes feed includes one more revision of a document after it stops matching a channel. It adds a removed property to the entry where this happens.". From what I can tell this this doesn’t seem to be the case (see below).

Here’s my example.

The document is created, and then modified once. Here’s the sync-gateway log:

CRUD+: Invoking sync on doc "-amxUwtw61wfrH8BT4YGdkn" rev 1-6526909bb79ef534ca5c6a18f24369c1
CRUD: 	Doc "-amxUwtw61wfrH8BT4YGdkn" in channels "{ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e}"
CRUD: Stored doc "-amxUwtw61wfrH8BT4YGdkn" / "1-6526909bb79ef534ca5c6a18f24369c1"
Events+: Event queue worker sending event Document change event for doc id: -amxUwtw61wfrH8BT4YGdkn to: Webhook handler [http://macbookpro.local:8080/datr/webhook]
HTTP:  #032: GET /sync_gateway/-amxUwtw61wfrH8BT4YGdkn  (as admin)
HTTP:  #033: PUT /sync_gateway/-amxUwtw61wfrH8BT4YGdkn  (as admin)
CRUD+: Invoking sync on doc "-amxUwtw61wfrH8BT4YGdkn" rev 2-9e48e80b8e341cc47af667992a7f8c4c
CRUD+: Saving old revision "-amxUwtw61wfrH8BT4YGdkn" / "1-6526909bb79ef534ca5c6a18f24369c1" (300 bytes)
CRUD+: Backed up obsolete rev "-amxUwtw61wfrH8BT4YGdkn"/"1-6526909bb79ef534ca5c6a18f24369c1"
CRUD: Stored doc "-amxUwtw61wfrH8BT4YGdkn" / "2-9e48e80b8e341cc47af667992a7f8c4c"
Events+: Event queue worker sending event Document change event for doc id: -amxUwtw61wfrH8BT4YGdkn to: Webhook handler [http://macbookpro.local:8080/datr/webhook]
Cache: Received deduplicated #558237 for ("-amxUwtw61wfrH8BT4YGdkn" / "2-9e48e80b8e341cc47af667992a7f8c4c")
Cache: Received #558240 after 1530ms ("-amxUwtw61wfrH8BT4YGdkn" / "2-9e48e80b8e341cc47af667992a7f8c4c")
Cache: Received #558240 after 1530ms ("-amxUwtw61wfrH8BT4YGdkn" / "2-9e48e80b8e341cc47af667992a7f8c4c")

And at this point the clients _changes feed looks like this:

{
  seq: 2057,
  id: "-amxUwtw61wfrH8BT4YGdkn",
  changes: [
    {
      rev: "2-9e48e80b8e341cc47af667992a7f8c4c"
    }
  ]
}

A change is then made to the document that results in the sync-function not assigning it to any channel (by not calling the channel function at all). Here’s the sync-gateway log:

CRUD+: Invoking sync on doc "-amxUwtw61wfrH8BT4YGdkn" rev 3-e563f1c7edacef0aa6709861f6222acd
CRUD+: Saving old revision "-amxUwtw61wfrH8BT4YGdkn" / "2-9e48e80b8e341cc47af667992a7f8c4c" (314 bytes)
CRUD+: Backed up obsolete rev "-amxUwtw61wfrH8BT4YGdkn"/"2-9e48e80b8e341cc47af667992a7f8c4c"
CRUD: 	Doc "-amxUwtw61wfrH8BT4YGdkn" in channels "{}"
CRUD: Stored doc "-amxUwtw61wfrH8BT4YGdkn" / "3-e563f1c7edacef0aa6709861f6222acd"
Events+: Event queue worker sending event Document change event for doc id: -amxUwtw61wfrH8BT4YGdkn to: Webhook handler [http://macbookpro.local:8080/datr/webhook]
Cache: Received #558246 after 668ms ("-amxUwtw61wfrH8BT4YGdkn" / "3-e563f1c7edacef0aa6709861f6222acd")

This line make me think it has been removed from the channel:

CRUD: Doc "-amxUwtw61wfrH8BT4YGdkn" in channels "{}"

And at this point the clients _changes feed looks like this:

{
  seq: 2062,
  id: "-amxUwtw61wfrH8BT4YGdkn",
  changes: [
    {
      rev: "3-e563f1c7edacef0aa6709861f6222acd"
    }
  ]
}

…no removed property. And the document (on the device) looks like this:

http://localhost:5984/dbname/-amxUwtw61wfrH8BT4YGdkn =>

{
  some_content: "blah",
  _id: "-amxUwtw61wfrH8BT4YGdkn",
  _rev: "3-e563f1c7edacef0aa6709861f6222acd"
}


FYI

It does look like the document is being removed from all channels in revision 3. Given that the client is still replicating revision 3, there are a few possibilities:

  1. The client user has been granted access to the * channel (and so has access to all documents)
  2. The client is replicating against the admin API endpoint, instead of the public API endpoint.

Thanks for the reply. I checked the user (using http://192.168.1.185:4985/sync_gateway/_user/user0) and the users don’t have access to channel *, but they do have access to a channel named “!” - what is that?:

{
name: "user0",
  all_channels: [
    "!",
    "ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e",
    "ch_9f32c47b-c126-4cd4-ad6a-155c5d330e20",
    "ch_private_user0",
    "ch_public_user0",
    "public"
  ]
}

And they definitely don’t see all documents in the system.

The IOS client is syncing on port 4984, which I believe is correct (the admin port is 4985 according to my sync-gateway config).

I left some information out… I’m running 2 sync- gateways. One for push and on for pull and I missed out the pull logs. Here they are from revision 3:

Cache: Received #558246 after 668ms ("-amxUwtw61wfrH8BT4YGdkn" / "3-e563f1c7edacef0aa6709861f6222acd")
Changes+: MultiChangesFeed sending &{Seq:558246 ID:-amxUwtw61wfrH8BT4YGdkn Deleted:false Removed:{ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e} Doc:map[] Changes:[map[rev:3-e563f1c7edacef0aa6709861f6222acd]] Err:<nil> allRemoved:true branched:false}   (to user0)
Changes+: MultiChangesFeed sending &{Seq:558246 ID:-amxUwtw61wfrH8BT4YGdkn Deleted:false Removed:{ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e} Doc:map[] Changes:[map[rev:3-e563f1c7edacef0aa6709861f6222acd]] Err:<nil> allRemoved:true branched:false}   (to user0)
Changes+: MultiChangesFeed sending &{Seq:558246 ID:-amxUwtw61wfrH8BT4YGdkn Deleted:false Removed:{ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e} Doc:map[] Changes:[map[rev:3-e563f1c7edacef0aa6709861f6222acd]] Err:<nil> allRemoved:true branched:false}   (to user0)
Changes+: MultiChangesFeed sending &{Seq:558246 ID:-amxUwtw61wfrH8BT4YGdkn Deleted:false Removed:{ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e} Doc:map[] Changes:[map[rev:3-e563f1c7edacef0aa6709861f6222acd]] Err:<nil> allRemoved:true branched:false}   (to user0)
Changes+: MultiChangesFeed sending &{Seq:558246 ID:-amxUwtw61wfrH8BT4YGdkn Deleted:false Removed:{ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e} Doc:map[] Changes:[map[rev:3-e563f1c7edacef0aa6709861f6222acd]] Err:<nil> allRemoved:true branched:false}   (to user0)
Changes+: MultiChangesFeed sending &{Seq:558246 ID:-amxUwtw61wfrH8BT4YGdkn Deleted:false Removed:{ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e} Doc:map[] Changes:[map[rev:3-e563f1c7edacef0aa6709861f6222acd]] Err:<nil> allRemoved:true branched:false}   (to user0)

The “!” channel is the public channel - all users have access to that by default.

There are a few things going on in that log - it looks like the same doc is being sent multiple times to user0. Do you have multiple replications running at once for user0?

Also, the doc is showing as a removal from channel ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e based on those logs. It might be helpful to make a curl request to :4984/sync_gateway/_changes as user0, and share both the response and the full log output from the request (preferably in a gist).

If the user has too much data to make that feasible, you could add since=558245 to limit the result set.

Thanks Adam.

The repeated sends to user0 are a think a bug in the app. The sync process when I restart the app during development, but i think the database remains running between restarts (so I’m getting multiple sync tasks). Anyway, that’s fixed now, but my problem persists.

Here the start of the output from the _:4984/sync_gateway/changes feed:

{"results":
  [
    {"seq":558246,"id":"-amxUwtw61wfrH8BT4YGdkn","removed":["ch_8a73ad6e-73f2-4bdb-a699-dd323ea9fb5e"],"changes":[{"rev":"3-e563f1c7edacef0aa6709861f6222acd"}]}, 
    {...

Do you need the whole output? if so I can wipe the data completely to keep it small.

Ok, i’ve wiped the data completely and started again. The doc id in question is -RuL_230Cbt1YMXdEyzYeTJ

The sync-gateway changes feed:

{"results":[
{"seq":2,"id":"_user/user0","changes":[]}
,{"seq":3,"id":"d3b5715165a8478ee35f5cb79815e65b","changes":[{"rev":"1-262f185da2ead1be547540836632950f"}]}
,{"seq":62,"id":"-p9MpeRCdxNOR7rV6ZsYp9d","changes":[{"rev":"1-b080e055c82df834cd16dc378ffaffb0"}]}
,{"seq":63,"id":"-QJ_TlBj4QvmlXQZinjwq9s","changes":[{"rev":"1-072526eea8a2d98b8a8e6624e888d1ea"}]}
,{"seq":64,"id":"-Q0vdcfQodmyZfX8mgbHyrl","changes":[{"rev":"2-3e7fe64343cb7fe8030f385d7a597001"}]}
,{"seq":68,"id":"-UvE-HiRGxvQi2p1BcE4iKe","changes":[{"rev":"3-a4746731a4f72652a91175282cd5b6f4"}]}
,{"seq":76,"id":"-RuL_230Cbt1YMXdEyzYeTJ","removed":["ch_b43e197b-64d5-4b82-9671-ef6e7567ab56"],"changes":[{"rev":"3-5c6dc6882aff5815bd8e09e280086076"}]}
,{"seq":77,"id":"-7EXj5thiHuLNWAb16ifBod","changes":[{"rev":"1-4ab2a10acf0a6c5c6f003ee68e453b51"}]}
,{"seq":78,"id":"-SSPLKX3FoGMwgVuTqG3_iU","changes":[{"rev":"1-404edc499066f8ccf5b6ac4efbfa3675"}]}
,{"seq":79,"id":"-zliHuJ8MRbNMWYcbO51beA","changes":[{"rev":"2-0c5ea0b2700ef7d8ab6aaf55ef271715"}]}
,{"seq":80,"id":"-EE0X1Fxcp80TsB2FqQpiFn","removed":["ch_b43e197b-64d5-4b82-9671-ef6e7567ab56"],"changes":[{"rev":"2-94f0a947386c11c69274b6e34a677523"}]}
,{"seq":81,"id":"-ki-UWJOe_0vsTqMVRQ3rCo","removed":["ch_b43e197b-64d5-4b82-9671-ef6e7567ab56"],"changes":[{"rev":"2-a52cce901c1a6c888de6773f2a95af02"}]}
,{"seq":83,"id":"-Ra0TqaVe0piuXT7eVc-zhR","changes":[{"rev":"4-c16c569fe0c64b61af6336d8ec46319d"}]}
,{"seq":88,"id":"ping","changes":[{"rev":"8-74db6b4b1293314da5ec58eb9ae019da"}]}
],
"last_seq":"88"}

The IOS client _changes feed (still no removed flag):

{
   "results":[
      {
         "seq":2,
         "id":"d3b5715165a8478ee35f5cb79815e65b",
         "changes":[
            {
               "rev":"1-262f185da2ead1be547540836632950f"
            }
         ]
      },
      {
         "seq":6,
         "id":"-p9MpeRCdxNOR7rV6ZsYp9d",
         "changes":[
            {
               "rev":"1-b080e055c82df834cd16dc378ffaffb0"
            }
         ]
      },
      {
         "seq":7,
         "id":"-QJ_TlBj4QvmlXQZinjwq9s",
         "changes":[
            {
               "rev":"1-072526eea8a2d98b8a8e6624e888d1ea"
            }
         ]
      },
      {
         "seq":8,
         "id":"-Q0vdcfQodmyZfX8mgbHyrl",
         "changes":[
            {
               "rev":"2-3e7fe64343cb7fe8030f385d7a597001"
            }
         ]
      },
      {
         "seq":12,
         "id":"-UvE-HiRGxvQi2p1BcE4iKe",
         "changes":[
            {
               "rev":"3-a4746731a4f72652a91175282cd5b6f4"
            }
         ]
      },
      {
         "seq":22,
         "id":"-RuL_230Cbt1YMXdEyzYeTJ",
         "changes":[
            {
               "rev":"3-5c6dc6882aff5815bd8e09e280086076"
            }
         ]
      },
      {
         "seq":23,
         "id":"-7EXj5thiHuLNWAb16ifBod",
         "changes":[
            {
               "rev":"1-4ab2a10acf0a6c5c6f003ee68e453b51"
            }
         ]
      },
      {
         "seq":24,
         "id":"-SSPLKX3FoGMwgVuTqG3_iU",
         "changes":[
            {
               "rev":"1-404edc499066f8ccf5b6ac4efbfa3675"
            }
         ]
      },
      {
         "seq":25,
         "id":"-EE0X1Fxcp80TsB2FqQpiFn",
         "changes":[
            {
               "rev":"2-94f0a947386c11c69274b6e34a677523"
            }
         ]
      },
      {
         "seq":26,
         "id":"-ki-UWJOe_0vsTqMVRQ3rCo",
         "changes":[
            {
               "rev":"2-a52cce901c1a6c888de6773f2a95af02"
            }
         ]
      },
      {
         "seq":27,
         "id":"-zliHuJ8MRbNMWYcbO51beA",
         "changes":[
            {
               "rev":"2-0c5ea0b2700ef7d8ab6aaf55ef271715"
            }
         ]
      },
      {
         "seq":29,
         "id":"-Ra0TqaVe0piuXT7eVc-zhR",
         "changes":[
            {
               "rev":"4-c16c569fe0c64b61af6336d8ec46319d"
            }
         ]
      },
      {
         "seq":31,
         "id":"_design\/dd_8",
         "changes":[
            {
               "rev":"5-814c42569a7b615dd7337372491f9257"
            }
         ]
      },
      {
         "seq":40,
         "id":"ping",
         "changes":[
            {
               "rev":"12-86f3cb8e9a930de762beee5d2c5850a2"
            }
         ]
      }
   ],
   "last_seq":40
}

The sync-gateway log:

 Cache: Received deduplicated #70 for ("-RuL_230Cbt1YMXdEyzYeTJ" / "2-3c31f3f6389f5ea33269900c952f364b")
 Cache: Received #73 after 1708ms ("-RuL_230Cbt1YMXdEyzYeTJ" / "2-3c31f3f6389f5ea33269900c952f364b")
 Changes+: MultiChangesFeed sending &{Seq:73 ID:-RuL_230Cbt1YMXdEyzYeTJ Deleted:false Removed:{} Doc:map[] Changes:[map[rev:2-3c31f3f6389f5ea33269900c952f364b]] Err:<nil> allRemoved:false branched:false}   (to user0)
 HTTP:  #020: GET /sync_gateway/-RuL_230Cbt1YMXdEyzYeTJ?rev=2-3c31f3f6389f5ea33269900c952f364b&revs=true&attachments=true  (as user0)
 Cache: Received #76 after 956ms ("-RuL_230Cbt1YMXdEyzYeTJ" / "3-5c6dc6882aff5815bd8e09e280086076")
 Changes+: MultiChangesFeed sending &{Seq:76 ID:-RuL_230Cbt1YMXdEyzYeTJ Deleted:false Removed:{ch_b43e197b-64d5-4b82-9671-ef6e7567ab56} Doc:map[] Changes:[map[rev:3-5c6dc6882aff5815bd8e09e280086076]] Err:<nil> allRemoved:true branched:false}   (to user0)
 CRUD+: Invoking sync on doc "-RuL_230Cbt1YMXdEyzYeTJ" rev 1-662bbf0b94c386859f584b4d454f4d81
 CRUD: 	Doc "-RuL_230Cbt1YMXdEyzYeTJ" in channels "{ch_b43e197b-64d5-4b82-9671-ef6e7567ab56}"
 CRUD: Stored doc "-RuL_230Cbt1YMXdEyzYeTJ" / "1-662bbf0b94c386859f584b4d454f4d81"
 Events+: Event queue worker sending event Document change event for doc id: -RuL_230Cbt1YMXdEyzYeTJ to: Webhook handler [http://macbookpro.local:8080/datr/webhook]
 HTTP:  #157: GET /sync_gateway/-RuL_230Cbt1YMXdEyzYeTJ  (as admin)
 HTTP:  #158: PUT /sync_gateway/-RuL_230Cbt1YMXdEyzYeTJ  (as admin)
 CRUD+: Invoking sync on doc "-RuL_230Cbt1YMXdEyzYeTJ" rev 2-3c31f3f6389f5ea33269900c952f364b
 CRUD+: Saving old revision "-RuL_230Cbt1YMXdEyzYeTJ" / "1-662bbf0b94c386859f584b4d454f4d81" (286 bytes)
 CRUD+: Backed up obsolete rev "-RuL_230Cbt1YMXdEyzYeTJ"/"1-662bbf0b94c386859f584b4d454f4d81"
 CRUD: Stored doc "-RuL_230Cbt1YMXdEyzYeTJ" / "2-3c31f3f6389f5ea33269900c952f364b"
 Events+: Event queue worker sending event Document change event for doc id: -RuL_230Cbt1YMXdEyzYeTJ to: Webhook handler [http://macbookpro.local:8080/datr/webhook]
 Cache: Received deduplicated #70 for ("-RuL_230Cbt1YMXdEyzYeTJ" / "2-3c31f3f6389f5ea33269900c952f364b")
 Cache: Received #73 after 1708ms ("-RuL_230Cbt1YMXdEyzYeTJ" / "2-3c31f3f6389f5ea33269900c952f364b")
 CRUD+: Invoking sync on doc "-RuL_230Cbt1YMXdEyzYeTJ" rev 3-5c6dc6882aff5815bd8e09e280086076
 CRUD+: Saving old revision "-RuL_230Cbt1YMXdEyzYeTJ" / "2-3c31f3f6389f5ea33269900c952f364b" (300 bytes)
 CRUD+: Backed up obsolete rev "-RuL_230Cbt1YMXdEyzYeTJ"/"2-3c31f3f6389f5ea33269900c952f364b"
 CRUD: 	Doc "-RuL_230Cbt1YMXdEyzYeTJ" in channels "{}"
 CRUD: Stored doc "-RuL_230Cbt1YMXdEyzYeTJ" / "3-5c6dc6882aff5815bd8e09e280086076"
 Events+: Event queue worker sending event Document change event for doc id: -RuL_230Cbt1YMXdEyzYeTJ to: Webhook handler [http://macbookpro.local:8080/datr/webhook]
 Cache: Received #76 after 956ms ("-RuL_230Cbt1YMXdEyzYeTJ" / "3-5c6dc6882aff5815bd8e09e280086076")
 Changes+: MultiChangesFeed sending &{Seq:76 ID:-RuL_230Cbt1YMXdEyzYeTJ Deleted:false Removed:{ch_b43e197b-64d5-4b82-9671-ef6e7567ab56} Doc:map[] Changes:[map[rev:3-5c6dc6882aff5815bd8e09e280086076]] Err:<nil> allRemoved:true branched:false}   (to user0)

That looks like things working as intended from the Sync Gateway side - the Sync Gateway changes feed is sending doc -RuL_230Cbt1YMXdEyzYeTJ with the removed property set.

When client replication subsequently attempts to retrieve that document (via bulk_get), it should be getting a version of the doc with the _removed:true property set.

I’ll need some help from @jens for insight on whether the iOS listener feed emits the removed flag, or if there’s another way to validate that the client has stored the removed revision with the expected _removed flag.

Couchbase Lite doesn’t treat _removed specially, it’ll just store it as a document property. A GET of the document+revID should show it.

I think the docs say that the changes feed in CBL should show removed=true for removals? Are they only talking about the _changes feed on the gateway, and not the internal CBL _changes feed? I believe deletes come through on the CBL feed as described, but not removals?

If so…

I tried a GET (using /-RuL_230Cbt1YMXdEyzYeTJ?rev=3-5c6dc6882aff5815bd8e09e280086076) but there’s no removed=true on there either, just revision 3 of the document.

Couchbase Lite’s _changes feed does not have a removed property; only Sync Gateway has that.

So apparently you do have access to revision 3 of the document, according to Sync Gateway. That implies that it was not removed from all channels you have access to. Is the document in other channels? Or does your account have access to the universal * channel?

The account doesn’t have access to *, they definitely don’t have access to all the docs in the system.

Revision 3 (the removed one) of the doc looks like this:

{
  "_sync": {
    "rev": "3-bd04b48266c700e5e3bd6470f772f990",
    "sequence": 1011,
    "recent_sequences": [
      1007,
      1010,
      1011
    ],
    "history": {
      "revs": [
        "1-f6318e399f2504633df48907e3bd10b3",
        "2-efe65fb770ea4f06bd05f93c53c72401",
        "3-bd04b48266c700e5e3bd6470f772f990"
      ],
      "parents": [
        -1,
        0,
        1
      ],
      "channels": [
        [
          "ch_f4f9f538-eca0-4856-a1fd-ccfe004ff6fa"
        ],
        [
          "ch_f4f9f538-eca0-4856-a1fd-ccfe004ff6fa"
        ],
        null
      ]
    },
    "channels": {
      "ch_f4f9f538-eca0-4856-a1fd-ccfe004ff6fa": {
        "seq": 1011,
        "rev": "3-bd04b48266c700e5e3bd6470f772f990"
      }
    },
    "time_saved": "2016-04-01T11:01:08.191391979+01:00"
  },
  "chat_group_id": "-SUDNzVFmFAq0kcWG9l02ru",
  "client_timestamp": 1459504859097,
  "content": {
    "message": "Hello",
    "type": "text"
  },
  "number_of_recipients": 1,
  "owner": "450ff26f-cc2f-49c8-a673-8533e0fdedd0",
  "server_timestamp": 1459504859643,
  "state": "archived",
  "type": "chat-message"
}

And again, the changes feed on the client looks like this:

{
  seq: 994,
  id: "-acrShIFSfKQtwm9o7CvYXM",
    changes: [
      {
        rev: "3-bd04b48266c700e5e3bd6470f772f990"
      }
    ]
},

What does the changes feed from Sync Gateway look like, or rather just the entry for that one revision? (You can use curl, httpie, etc. to fetch it; just make sure to authenticate as the correct user.)

I’ve posted an example of the changes feed from the sync gateway above. The removed flag is present.

I’ve had another look into this. It seems that the behaviour is that the _removed flag does not appear on the device that caused the removal, but it does appear on other devices that have access to the document. Is this by design?

I think this is the expected behaviour - since the client is the originator of the revision triggering the removal, (and so already has a copy of the revision that’s triggering the removal), that revision won’t get replaced during pull replication.

Some additional discussion in this comment:

Ok thanks. I’ve been trying to get to the bottom of this for weeks now. I think the docs could do with a more detailed explanation.