Syncing documents in 2 views
I got quite some requests on the details of the syncing documents in views pattern/anti-pattern.So this is what you need to do:
- Have 2 views with identical keys, sorted by the key
- Julian's OpenLog database
- The main function SyncAllDocument
- 3 auxiliary functions: getCompareKeySource, getCompareKeyTarget and updateSourceDoc
Option Public Option Declare Use "OpenLogFunctions" Function getCompareKey(doc As NotesDocument) As String getCompareKey = doc.getitemvalues("someidfield")(0) End Function Sub updateSourcedoc(curDoc As NotesDocument, newDoc As NotesDocument) 'We only save if the items have changed! Dim saveFlag As Boolean Dim curItem As NotesItem Dim newItem As NotesItem On Error Goto Err_updateSourcedoc saveFlag = False Forall it In newDoc.Items Set newItem = it If curDoc.HasItem(newItem.Name) Then Set curItem = curDoc.GetFirstItem(newItem.Name) If curItem.Text <> newitem.Text Then Call curItem.Remove Call newItem.CopyItemToDocument(curDoc,newItem.Name) saveFlag = True End If Else Call newItem.CopyItemToDocument(curDoc,newItem.Name) saveFlag = True End If End Forall 'Todo Optional: remove items that don't exist anymore If saveFlag Then Call curDoc.Save(True,True) End If Exit_updateSourcedoc: Exit Sub Err_updateSourcedoc: Call LogErrorEx("",SEVERITY_HIGH,curDoc) Resume Exit_updateSourcedoc End Sub Function SyncAllDocuments(sourceView As NotesView, targetView As NotesView) As Boolean 'The documents to be compared Dim SourceDoc As NotesDocument Dim nextSourceDoc As NotesDocument Dim targetDoc As NotesDocument Dim nextTargetDoc As NotesDocument 'Auxiliary variables Dim gotoNextSource As Boolean Dim gotoNextTarget As Boolean Dim sourceKey As String Dim targetKey As String On Error Goto Err_SyncAllDocuments 'Important: the two views are designed that at the end of this algorythm both views have the same number of documents 'with the same data in it. gotoNextSource = True 'We need to set this to get the loop started gotoNextTarget = True 'We need to set this to get the loop started Set sourceDoc = SourceView.GetFirstDocument Set targetDoc = TargetView.GetFirstDocument 'This is the outer loop running through the documents in this database 'The "inner" loop is for the target database Do Until sourceDoc Is Nothing If gotoNextSource Then 'Since we just advanced to the current source we need to know the next one Set nextSourceDoc = SourceView.GetNextDocument(sourceDoc) 'This must be BEFORE any action with the doc End If If targetDoc Is Nothing Then 'We don't have any target documents, so we copy point blank Call sourceDoc.CopyToDatabase(targetView.Parent) gotoNextSource = True 'We can read the next source document gotoNextTarget = False 'We are already at nothing for the target Else 'Since targetdocument exists we can get the next target document now if we need it If gotoNextTarget Then 'Since we just advanced to the current target we need to know the next one Set nextTargetDoc = targetView.GetNextDocument(targetDoc) 'This must be BEFORE any action with the doc End If 'Now we need to compare the keys sourceKey = getCompareKeySource(sourceDoc) targetKey = getCompareKeyTarget(targetDoc) If sourceKey = targetKey Then 'We found an existing document and would need to update it if values have changed Call updateSourcedoc(sourceDoc, targetDoc) 'We can move our pointer one up for source and target documents gotoNextSource = True gotoNextTarget = True Elseif sourceKey > targetKey Then 'We found a document that doesn't exist in the source database anymore 'so we need to remove that from the target database Call targetDoc.Remove(True) gotoNextSource = False 'We stay on the source until we get even or less with the key gotoNextTarget = True 'We just removed the document Else 'We have a source document that is not yet in the target database, We just copy it over. Call sourceDoc.CopyToDatabase(targetView.Parent) gotoNextSource = True 'We just copied this document we move on gotoNextTarget = False 'They key was too big, so we need to wait End If End If 'Advance the pointers If gotoNextSource Then Set sourceDoc = nextSourceDoc End If If gotoNextTarget Then Set targetDoc = nextTargetDoc End If Loop 'Finally we need to remove all documents in the target view that are still here since 'We ran out of source documents 'If we ran out of target documents already targetDoc is nothing aready Do Until targetDoc Is Nothing Set nextTargetDoc = targetView.getNextDocument(targetDoc) Call targetDoc.Remove(True) Set targetDoc = nextTargetDoc Loop SyncAllDocuments = True 'If we got here it worked Exit_SyncAllDocuments: Exit Function Err_SyncAllDocuments: SyncAllDocuments = False LogError Resume Exit_SyncAllDocuments End Function Function getCompareKeySource(doc As NotesDocument) As String getCompareKeySource = getCompareKey(doc) End Function Function getCompareKeyTarget(doc As NotesDocument) As String getCompareKeyTarget = getCompareKey(doc) End Function
provided by Julian Robichaux at nsftools.com.






Comments
thx for pointing out. You are right. Code fixed.
Posted by Stephan H. Wissel At 15:02:36 On 09/24/2007 | - Website - |
one small logic typo... in the inner loop of the SyncAllDocuments function.
Right after If targetDoc is Nothing, you're setting gotoNextSource twice.
I'm thinking that you meant gotoNextSource = True, and then gotoNextTarget = False.
You may want to make a small edit, just in case someone tries to cut-and-paste the code.
Cheers.
Posted by William Ryken At 08:03:51 On 09/24/2007 | - Website - |
What I am about to mention takes away some of the "dynamicness" of the code, but if you are running into performance issues...just throwing another idea out there...
If the documents that have changed versus total docs in the view is small, in the updateSourceDoc routine, what you can also do is have column 2 of each view concactenate the fields, e.g.
View1, column2 = Field1 + "~" + Field2 + "~" + @Implode(MultiField1;"^") + Field4...etc,
View2 column2 = Field1 + "~" + Field2...
Since the docs are in a view, you can compare the doc.ColumnValues( 1 ), and if they are different, then start the cycle through the fields. This should speed up the iteration. If you used NotesViewEntries, and only referenced the NotesDocument if you began the iteration through the NotesItems, this should speed it up even more. The side effect will be that the view indeces will go up on each view, plus it's only checking if the fields you have concatenated in the view column have changed.
Posted by Nick Wall At 20:12:16 On 09/24/2007 | - Website - |