Экспорт в CSV - все документы в коллекции с отсортированными элементами

Любой, кто использовал плохо спроектированную / поддерживаемую базу данных лотосных заметок, может засвидетельствовать, что не все записи с одинаковым именем формы имеют одинаковое количество элементов или даже порядок элементов.

Возникла необходимость экспортировать всю базу данных в CSV-файлы для миграции, и я собирал кусочки из разных форумов и блогов, чтобы добиться этого.

У меня есть рабочая модель кода, но она требует ручного редактирования для создания коллекции для каждой формы. Что хорошо, но не так аккуратно, как хотелось бы.

Кто-нибудь знает способ динамического создания новой коллекции на основе данных, извлеченных из основной коллекции / записи.

Весь кодовый набор ниже

    'Whole database export via collection with Sorted items, created by CodeJack 
'Export CSV based on http://searchdomino.techtarget.com/tip/How-to-export-data-from-a-Lotus-Notes-database-to-a-CSV-file
'sortValues based on http://per.lausten.dk/domino/sortNotesDocumentCollection.html

    Sub Initialize

        On Error Goto processerror

        Dim session As New NotesSession
        Dim dbPri As NotesDatabase
        Dim ws As New NotesUIWorkspace
        Dim dc As NotesDocumentCollection
        Dim docPri As NotesDocument
        Dim curView As NotesUIView
        Dim NumRec As String
        Dim msgOutputs As String


        'Get useable date and time values for file naming
        Dim fDate As String
        Dim fTime As String

        If Month(Date()) < 10 Then 
            If Day(Date()) < 10 Then
                fDate = Year(Date()) & "0" & Month(Date()) & "0" & Day(Date())
            Else
                fDate = Year(Date()) & "0" & Month(Date()) & Day(Date())
            End If
        Else
            If Day(Date()) < 10 Then
                fDate = Year(Date()) & Month(Date()) & "0" & Day(Date())
            Else
                fDate = Year(Date()) & Month(Date()) & Day(Date())
            End If      
        End If

        fTime = Hour(Time()) & "-" & Minute(Time())

        'Set the NewLine variable for breaking message boxes
        Dim NewLine As String
        NewLine = Chr(10)+Chr(13)

        'declare the Pri database
        Set dbPri = session.CurrentDatabase
        Set curView = ws.CurrentView

        'Set the Primary DB collection to retrieve the list of selected documents in the view
        Set dc = curView.Documents

        'Collection1s collection
        Dim dcCollection1 As NotesDocumentCollection    
        Dim docCollection1 As NotesDocument
        Dim NumCollection1 As String

        'Collection2 collection
        Dim dcCollection2 As NotesDocumentCollection    
        Dim docCollection2 As NotesDocument
        Dim NumCollection2 As String

        'Open collections
        If dbPri.IsOpen Then
            Set dcCollection1 = dbPri.CreateDocumentCollection
            Set dcCollection2 = dbPri.CreateDocumentCollection
        Else
            Msgbox "Database has not been opened"
            Exit Sub
        End If

        'Set Export path
        Dim sFilepath As String
        Dim sFilename As String
        sFilepath = "C:\Data\Testing\"

        'Continue if collection has documents
        NumRec = dc.Count

        If NumRec > 0 Then
            msgOutputs = NumRec & " records processed." & NewLine
                'Split out documents to their individual Collections
            If (Not dc Is Nothing) Then

                For a = 1 To dc.Count 'a = all documents
                    Set docPri = dc.GetNthDocument(a)

                'Assign document to relevant collection based on the form name
                    If docPri.Form(0) = "VID" Then
                        Call dcCollection1.AddDocument (docPri)

                    Elseif docPri.Form(0) = "SI" Then
                        Call dcCollection2.AddDocument (docPri)

                    End If

                Next
            End If
        Else
            Msgbox  "No records in collection"
            Exit Sub
        End If


        'Process Collection1
        'Count # of records in collection 
        NumCollection1 = dcCollection1.Count

        'Continue if collection has documents
        If NumCollection1 > 0 Then
            'Compile output message
            msgOutputs = msgOutputs & NumCollection1 & " - " & dcCollection1.GetFirstDocument.Form(0) & "'s" & NewLine

            'Set the export filename
            sFilename = dcCollection1.GetFirstDocument.Form(0) & "_" & fDate &"_" & fTime & ".csv"

    'Export Collection
    Call exportCSV(dcCollection1, sFilepath, sFilename) 
        End If


        'Process Collection2
        NumCollection2 = dcCollection2.Count

        'Continue if collection has documents
        If NumCollection2 > 0 Then      

        'Compile output message
            msgOutputs = msgOutputs & NumCollection2 & " - " & dcCollection2.GetFirstDocument.Form(0) & "'s" & NewLine

                'Set the export filename        
            sFilename = dcCollection2.GetFirstDocument.Form(0) & "_" & fDate &"_" & fTime & ".csv"      

    'Export Collection
            Call exportCSV(dcCollection2, sFilepath, sFilename) 
        End If


        'Display output message to user
        Msgbox msgOutputs


        Exit Sub    

    processerror:
        If Err <> 0 Then
            Msgbox "Initialize: ERROR on line " & Cstr(Erl) & " (" & Cstr(Err) & ") - " & Error$

            Exit Sub

        End If

    End Sub

    Sub exportCSV(col As NotesDocumentCollection,  sFilepath As String, sFilename As String)
    'CSV write method based on http://searchdomino.techtarget.com/tip/How-to-export-data-from-a-Lotus-Notes-database-to-a-CSV-file  
    'Altered by Andrew Lambert to fit purpose of sorting and exporting all items on documents in a collection

        On Error Goto processerror

        Dim datadoc As NotesDocument
        Dim sorteddoc As NotesDocument  
        Dim db As NotesDatabase
        Dim session As New NotesSession 
        Dim fileNum As Integer
        Dim fileName As String
        Dim headerstring As String
        Dim values As String
        Dim item As NotesItem
        Dim ItemName As String

        Dim arSort As Variant

        Set db = session.CurrentDatabase

        fileNum% = Freefile()
        fileName$ = sFilepath & sFilename

        Open fileName$ For Output As fileNum%

    'Build Files

        If (Not col Is Nothing) Then
            For i = 1 To col.Count 
                Set datadoc = col.GetNthDocument(i)

    'Write record header to file            

                Forall x In datadoc.Items
                    If x.type = 1084 Or x.name = "Photograph" Or x.name = "Signature" Then 'Skip data types / fields which cant be exported via CSV
                    'Do nothing
                    Else
                        headerstring=headerstring & |"| & x.name &|",|  'Create header string for the record
                    End If

                End Forall

                'remove trailing comma
                headerstring=Left(headerstring,Len(headerstring)-1)

                'break headerstring into components for array
                arSort = Split(headerstring,",")

                'Sort array alphabetically
                arSort = sortValues(arSort)

                'Compile sorted array back into string
                headerstring = Implode(arSort,",")

                'remove trailing "
                headerstring=Left(headerstring,Len(headerstring)-1)

                'Write to file
                Write #fileNum%,  |Header","UNID",| & headerstring & ||
                headerstring=""

                'Create sorted document for exporting data, this is needed as you can't sort the values of the items separate from the item names
                Set sorteddoc = db.CreateDocument

                'Loop through sorted array of item names
                Forall z In arSort
                    ItemName = Replace(z,|"|,||) 'Remove quotations to avoid ADT error

                    'Copy item from source document to destination in alphabetical order
                    Call sorteddoc.CopyItem(datadoc.GetFirstItem(ItemName),ItemName) 

                End Forall

    'Write record data to file          

                'loop through all document items
                Forall x In sorteddoc.Items             
                    'retrieve item value
                    values=values & |"| & x.text &|",| 
                End Forall

                'Write to file
                Write #fileNum%,  |Data",| & |"| & sorteddoc.UniversalID & |",| & values & |"|
                values=""

            Next
        End If
        Close fileNum%



        Exit Sub

    processerror:
        If Err <> 0 Then
            Msgbox "Export CSV: ERROR on line " & Cstr(Erl) & " (" & Cstr(Err) & ") - " & Error$
            Exit Sub

        End If

    End Sub

    Function sortValues(varValues As Variant) As Variant
        'from http://per.lausten.dk/domino/sortNotesDocumentCollection.html

        On Error Goto errHandler
        ' Use Shell sort to sort input array and return array sorted ascending

        Dim k As Integer
        Dim i As Integer
        Dim j As Integer
        Dim h As Integer
        Dim r As Integer
        Dim temp As String


         'Set up for Shell sort algorithm
        k = Ubound( varValues )
        h = 1
        Do While h < k
            h = (h*3)+1
        Loop
        h = (h-1)/3
        If h > 3 Then
            h = (h-1)/3
        End If

         'Shell sort algorithm
        Do While h > 0
            For i = 1+h To k
                temp = varValues(i)
                j = i-h
                Do While j >0
                    If varValues(j)>temp Then
                        varValues(j+h) = varValues(j)
                        varValues(j) = temp
                    Else
                        Exit Do
                    End If
                    j = j-h
                Loop
            Next i
            h = (h-1)/3
        Loop

         'Write new sorted values    
        sortValues = varValues

    getOut:
        Exit Function

    errHandler:
        Dim strMsg As String
        strMsg = "SortValues: Error #" & Err & Chr$(10) & Error$ & Chr$(10) & "Line #" & Erl & | in sub/function: "| & Lsi_info(2) & |"|
        Msgbox strMsg, 16, "Unexpected error"
        sortValues = "ERROR"
        Resume getOut

    End Function

1 ответ

Прежде всего: не используйте GetNthDocument в NotesDocumentCollections, это делает вещи невероятно медленными, так как отсчитывает от 0 в каждом раунде... Время увеличивается экспоненциально с увеличением размера коллекции.

Вместо

For i = 1 to dc.Count
  Set doc = dc.GetNthDocument(i)
Next

использование

Set doc = dc.GetFirstDocument()
While not doc is Nothing
  '- do your stuff here
  Set doc = dc.GetNextDocument(doc)
Wend

Тем не менее, существуют разные способы создания коллекций.

Я бы предложил использовать список коллекций, чтобы быть полностью гибким:

Dim ldc List as NotesDocumentCollection

Если у вас есть имя форм, которые вы хотите экспортировать в массив (varForms в примере), то вы можете сделать что-то вроде этого:

Forall strForm in varForms
  Set ldc( strForm ) = dbPri.Search( {Form = "} & strForm & {"}, Nothing, 0)
End Forall

Как указано в комментарии Ричарда (спасибо), вы можете просто получить все формы в базе данных, используя

varForms = dbPri.Forms

Таким образом, вам не нужно представление, содержащее все документы, которые вы хотите экспортировать.

Если вы хотите "разделить" существующую коллекцию (как в вашем примере), вы можете сделать что-то вроде этого:

Set doc = dc.GetFirstDocument()
While not doc is Nothing
  strForm = doc.GetitemValue( "form" )(0)
  If Not iselement( ldc( strForm ) ) then
    Set ldc( strForm ) = dbPri.CreateDocumentCollection
  End If
  Call ldc(strForm).AddDocument( doc )
  Set doc = dc.GetNextDocument(doc)
Wend

А позже вы можете запустить все коллекции:

Forall dcForm in ldc
  Set docWork = dcForm.GetFirstDocument()
  While not docWork is Nothing
    '- do your stuff here
    Set docWork = dcForm.GetNextDocument(docWork)
  Wend
End Forall

Надеюсь, что это даст вам отправную точку

Другие вопросы по тегам