I made a mass edit to a bunch of docs in my couchdb, but I made a mistake and overwrote a field improperly. I can see that the previous revision is there. How do I revert back to it?
My current best guess, based on this:
http://guide.couchdb.org/draft/conflicts.html
...is to find the doc id and the revision id and then send a delete for that document specifying the revision I want to be gone.
curl -X DELETE $HOST/databasename/doc-id?rev=2-de0ea16f8621cbac506d23a0fbbde08a
I think that will leave the previous revision. Any better ideas out there?
I had to write some coffeescript (using underscore.js and jquery.couch) to do this. It's not a true revert, as we are getting the old revision and creating a new revision with it. Still looking for better suggestions:
_.each docsToRevert, (docToRevert) ->
$.couch.db("databaseName").openDoc docToRevert.id,
revs_info: true
,
success: (doc) ->
$.couch.db("databaseName").openDoc docToRevert.id,
rev: doc._revs_info[1].rev #1 gives us the previous revision
,
success: (previousDoc) ->
newDoc = previousDoc
newDoc._rev = doc._rev
result.save newDoc
Related
I have versioning and checkin/checkout enabled in a SharePoint 2010 list, and for business-related reasons, would like to update information in a field: overwriting the field data for all versions in a similar manner and in place so that the version numbers do not change.
If I call SPListItemVersion.ListItem.UpdateOverwriteVersion(), it fails stating that I need to check out the item before making changes to it. Makes sense. So I precede the update statement with SPListItemVersion.ListItem.CheckOut() statement, attempt the update, and receive an error that I cannot overwrite a published version. I've also attempted to precede the check out with SPSite.AllowUnsafeUpdates = true, setting it back to false after the update call, but the latter error still occurs. Any ideas?
Stripped code below:
foreach (SPListItemVersion itemVersion in item.Versions){
itemVersion.ListItem.File.CheckOut(SPFile.SPCheckOutType.Online, itemVersion.ListItem.File.TimeLastModified.ToString());
site.AllowUnsafeUpdates = true;
itemVersion.ListItem["FieldName"] = "changed value here";
itemVersion.ListItem.UpdateOverwriteVersion();
site.AllowUnsafeUpdates = false;
itemVersion.ListItem.File.CheckIn("Updated list item version", SPCheckinType.OverwriteCheckIn);
}
To anyone that may find themselves facing this issue, you do not need to toggle the AllowUnsafeUpdates field. What worked for me is replacing the itemVersion.ListItem.UpdateOverwriteVersion() statement with itemVersion.ListItem.SystemUpdate(false). The parameter passed in tells SharePoint to not create a new version when updating.
Edit: This answer only updates the current item again. SPListItemVersion field references are available via a get only; it appears this is not possible in the object model.
I have a mongoose setup which involves an embedded-schema, lets say: A Blogpost with embedded comments. Comments can be edited by the original publisher as well as by an editor/admin. After adding / editing a comment the entire blogpost is saved.
I have some custom mongoose's 'pre' middleware set up on the embedded comment-schema which automatically sets the lasteditdate for that particular comment.
The thing is that 'pre' is called on EVERY comment on the blogpost, since I call save() on the blogpost. (For other reasons I need to do it like this) . Therefore, I need a way to check which comments have changed (or are new) since they were last saved (as part of the Blogpost overall save())
The questio: how to check in 'pre' whether a comment has changed or not? Obviously calling this.isNew isn't sufficient, since comments could be edited (i.e: aren't new) as well.
Is there any isDirty or similar that I'm overlooking?
For version 3.x
if(doc.isModified()){
// do stuff
}
In Mongoose you can use the Document method isModified(#STRING).
The most recent documentation for the method can be found here.
So to check a specific property with doc.isModified you can do this:
doc.comments[4].message = "Hi, I've made an edit to my post";
// inside pre hook
if ( this.isModified('comments') ) {
// do something
}
If you want to check a specific comment you can do that with the following notation this.isModified('comments.0.message')
Since the argument takes a string if you needed to know specifically which comment was modified you could loop through each comment and run this.isModified('comments['+i+']message')
You may use the modified getter:
if (doc.modified) {
// :)
}
This may be relevant to Mongoose users circa mid-2020 who are seeing this error:
"errorType": "TypeError",
"errorMessage": "Cannot set property 'isDirty' of null",
Upgrade to the latest version of Mongoose to fix it.
https://github.com/Automattic/mongoose/issues/8719
I've read a bit about CouchDB and I'm really intrigued by the fact that it's "append-only". I may be misunderstanding that, but as I understand it, it works a bit like this:
data is added at time t0 to the DB telling that a user with ID 1's name is "Cedrik Martin"
a query asking "what is the name of the user with ID 1?" returns "Cedrik Martin"
at time t1 an update is made to the DB telling: "User with ID 1's name is Cedric Martin" (changing the 'k' to a 'c').
a query asking again "what is the name of the user with ID 1" now returns "Cedric Martin"
It's a silly example, but it's because I'd like to understand something fundamental about CouchDB.
Seen that the update has been made using an append at the end of the DB, is it possible to query the DB "as it was at time t0", without doing anything special?
Can I ask CouchDB "What was the name of the user with ID 1 at time t0?" ?
EDIT the first answer is very interesting and so I've got a more precise question: as long as I'm not "compacting" a CouchDB, I can write queries that are somehow "referentially transparent" (i.e. they'll always produce the same result)? For example if I query for "document d at revision r", am I guaranteed to always get the same answer back as long as I'm not compacting the DB?
Perhaps the most common mistake made with CouchDB is to believe it provides a versioning system for your data. It does not.
Compaction removes all non-latest revisions of all documents and replication only replicates the latest revisions of any document. If you need historical versions, you must preserve them in your latest revision using any scheme that seems good to you.
"_rev" is, as noted, an unfortunate name, but no other word has been suggested that is any clearer. "_mvcc" and "_mcvv_token" have been suggested before. The issue with both is that any description of what's going on there will inevitably include the "old versions remain on disk until compaction" which will still imply that it's a user versioning system.
To answer the question "Can I ask CouchDB "What was the name of the user with ID 1 at time t0?" ?", the short answer is "NO". The long answer is "YES, but then later it won't work", which is just another way of saying "NO". :)
As already said, it is technically possible and you shouldn't count on it. It isn't only about compaction, it's also about replication, one of CouchDB's biggest strengths. But yes, if you never compact and if you don't replicate, then you will be able to always fetch all previous versions of all documents. I think it will not work with queries, though, they can't work with older versions.
Basically, calling it "rev" was the biggest mistake in CouchDB's design, it should have been called "mvcc_token" or something like that -- it really only implements MVCC, it isn't meant to be used for versioning.
Answer to the second Question:
YES.
Changed Data is always Added to the tree with a higher revision number. same rev is never changed.
For Your Info:
The revision (1-abcdef) ist built that way: 1=Number of Version ( here: first version),
second is a hash over the document-content (not sure, if there is some more "salt" in there)...
so the same doc content will always produce the same revision number ( with the same setup of couchdb) even on other machines, when on the same changing-level ( 1-, 2-, 3-)
Another way is: if you need to keep old versions, you can store documents inside a bigger doc:
{
id:"docHistoryContainer_5374",
"doc_id":"5374",
"versions":[
{"v":1,
"date":[2012,03,15],
"doc":{ .... doc_content v1....}
},
{"v":2,
"date":[2012,03,16],
"doc":{ .... doc_content v2....}
}
]
}
then you can ask for revisions:
View "byRev":
for (var curRev in doc.versions) {
map([doc.doc_id,doc.versions[curRev].v],doc.versions[curRev]);
}
call:
/byRev?startkey=["5374"]&endkey=["5374",{}]
result:
{ id:"docHistoryContainer_5374",key=[5374,1]value={...doc_content v1 ....} }
{ id:"docHistoryContainer_5374",key=[5374,2]value={...doc_content v2 ....} }
Additionaly you now can write also a map-function that amits the date in the key, so you can ask for revisions in a date-range
t0(t1...) is in couchdb called "revision". Each time you change a document, the revision-number increases.
The docs old revisions are stored until you don't want to have old revisions anymore, and tell the database "compact".
Look at "Accessing Previous Revisions" in http://wiki.apache.org/couchdb/HTTP_Document_API
How can I delete a document from couchdb using CouchRest, I have the document id. I guess it is something simple I am missing here.
I tried -
CouchRest.delete("http://localhost:5984/db/docid")
It throws an RestClient::ResourceNotFound: 404 Resource Not Found:
Could anybody throw some light on this issue please.
Cheers
You cannot delete a document without knowing its _rev.
I don't use CouchRest, but according to your code, you may append a _rev query parameter like this:
CouchRest.delete("http://localhost:5984/db/docid?_rev=docrev")
In order to delete the document you need to know what its revision number is, and then send this back with the delete request. Easiest way to accomplish this is just to get the whole document and then call destroy on that document:
CouchRest.database("http://localhost:5984/databasename").get(doc_id).destroy()
Access CouchDB
couch = CouchRest.new("http://localhost:5984")
db = couch.database('db-name')
timestamp = Time.now
Save a document, with ID
db.save_doc('_id' => 'doc', 'name' => 'test', 'date' => timestamp)
Fetch doc
doc = db.get('doc')
puts doc.inspect # #
Delete
db.delete_doc(doc)
I know I can retrieve all revisions of an "available" document, but can I retrieve the last "available" version of a deleted document? I do not know the revision id prior to the delete. This is the command I am currently running...it returns {"error":"not_found","reason":"deleted"}.
curl -X GET http://localhost:5984/test_database/a213ccad?revs_info=true
I've got this problem, trying to recover deleted document, here is my solution:
0) until you run a compaction, get deleted history, e.g.:
curl http://example.iriscouch.com/test/_changes
1) you'll see deleted documents with $id and $rev, put empty document as new version, e.g.:
curl -X PUT http://example.iriscouch.com/test/$id?rev=$rev -H "Content-Type: application/json" -d {}
2) now you can get all revisions info, e.g:
curl http://example.iriscouch.com/test/$id?revs_info=true
See also Retrieve just deleted document
Besides _changes, another good way to do this is to use keys with _all_docs:
GET $MYDB/_all_docs?keys=["foo"] ->
{
"offset": 0,
"rows": [
{
"id": "foo",
"key": "foo",
"value": {
"deleted": true,
"rev": "2-eec205a9d413992850a6e32678485900"
}
}
],
"total_rows": 0
}
Note that it has to be keys; key will not work, because only keys returns info for deleted docs.
You can get the last revision of a deleted document, however first you must first determine its revision id. To do that, you can query the _changes feed and scan for the document's deletion record — this will contain the last revision and you can then fetch it using docid?rev=N-XXXXX.
I remember some mailinglist discussion of making this easier (as doing a full scan of the changes feed is obviously not ideal for routine usage), but I'm not sure anything came of it.
I've hit this several times recently, so for anyone else wandering by ...
This question typically results from a programming model that needs to know which document was deleted. Since user keys such as 'type' don't survive deletion and _id is best assigned by couch, it would often be nice to peak under the covers and see something about the doc that was deleted. An alternative is to have a process that sets deleted:True (no underscore) for documents, and to adjust any listener filters, etc., to look for deleted:True. One of the processes can then actually delete the document. This means that any process triggering on the document doesn't need to track an _id for eventual deletion.