Searching Lotus Notes Databases - search

I have around 50 lotus notes databases which I need to search through (including RTFs and attachments) based on a rather complicated query (for example: If customer = a or b or c or d or e ... or z & product = x or y) then == match; and a tag to (e.g. tag = found or not found)
However, I wasn't sure the best way to go about this and wanted to check three options.
Using Lotus' 'Search in View' should, after indexing, search all the databases - however I am unsure if it will accept a long, complicated search query
Coding an agent in Lotus SCRIPT to basically perform the search in 1. but this might be a way of getting it to accept a complicated query
Using external software (e.g. X1 Professional Search) to search outside of Lotus Notes (however I am not sure if I will be able to tag the files if I identify them in windows explorer).
Edit: My idea is:
Sub Initialise
Dim session as New NotesSession
Dim db as NotesDatabase
Dim dc as NotesDocumentCollection
Dim doc as NotesDocument
Dim searcy_query$
'On current database
Set db = session.CurrentDatabase
'Force index of database
Call db.UpdateFTIndex(True)
'Construct QUERY
search_query = "(Customer1|Customer2) & (Product1|Product2)"
'Search
Set dc = db.FTSearch(query, 0)
If dc.Count=0 Then
Msgbox "No matches!"
Exit Sub
End If
‘Tag the matched documents with “Flag”
Call dc.StampAll("Flag","Active)")
End Sub
However, I am not sure if this will return all matches and also regarding #TRIM and #UPPER (where to put them into the query as I will be searching all fields and RTFs rather than specific ones)

First of all: Searching more than one database at a time can of course be done "manually" by searching each individual database, collection the results and find a way to present the documents "somehow" (what will not be easy, as documents from different databases cannot be shown in "one" view - you would need to use "shadow- documents" or a web- approach (e.g. XPages))
BUT: Lotus Notes has a built-in function to do this, it is called "Domain Indexer". You can read more about how to setup "domain index" in this IBM Link or in your administration help.
Examples for using the domain- index for multi- database- searches can be found in catalog.nsf in the form "DomainQuery".
The search- string does not have a limit as far as I know, so that you can do very complex searches with this technique and it gives you all the matches.
If you search for a LotusScript- Solution, check the documentation for NotesDatabase.ftdomainsearch for example code like this (taken from developer help):
The following code, when placed in a button on a search form within a directory catalog database, searches the directory for the specified query string, and returns all results.
Sub Click(Source As Button)
Dim s As New NotesSession
Dim db As NotesDatabase
Dim w As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Dim doc as NotesDocument
Dim quer As String
Dim srdoc as NotesDocument
Set db=s.CurrentDatabase
Set uidoc = w.currentdocument
uidoc.refresh
Set doc=uidoc.Document
quer=doc.query(0)
On Error Resume Next
If db.isopen Then
If Err <> 0 Then
Messagebox STR_DBOPEN_ERROR, 0 , STR_ERROR
Err = 0
Exit Sub
End If
Set srdoc = db.ftdomainsearch(quer, 0)
If Err <> 0 Then
Messagebox STR_NDF , 0 , STR_LOTUS_NOTES
Err=0
Exit Sub
End If
srdoc.Form="SearchResults"
Call w.EditDocument(False, srdoc, True)
End If
End Sub

If you also intend to search Rich Text, the simplier way is Full Text Search, you got the point!
The syntax for your query is:
generic_text or ([_CreationDate]<07.10.2014 and ([CustomerFieldName]="Smith" or [CustomerFieldName]="Wesson"))
For formating the Result, I'ld suggest looking at:AppendDocLink for something like:
Dim session As New NotesSession
Dim db As New NotesDatabase("", "resu.nsf")
Dim newDoc As NotesDocument
Dim rtitem As NotesRichTextItem
Dim dc As NotesDocumentCollection
Dim doc As NotesDocument
Set newDoc = New NotesDocument( db )
Set rtitem = New NotesRichTextItem( newDoc, "Body" )
'you have to loop on your 50 DBs
'Search =>from your code
Set dc = db.FTSearch(query, 0)
while not doc is nothing
Call rtitem.AppendDocLink( doc, db.Title )
Call rtitem.AddTab( 1 )
Call rtitem.AppendText( doc.FieldImportantInResult( 0 ) )
Call rtitem.AddNewLine( 1 )
Set doc = dc.GetNextDocument( doc )
Wend
newDoc.save true, true
'this part is not to add it you plane to run your search in background
Dim w As New NotesUIWorkspace
Call w.EditDocument(False, newDoc, True)

Related

Getting a value from Embedded View in Lotus Notes

I have probably a very simple problem but got stuck on it
I have a form inside it i have a field and for it i want to take value from a embedded view has anybody a idea how to accomplish it.
Getting a value from an embedded view from the "surrounding" document is not possible. But the opposite direction definitely is.
In the code of all events / actions in the embedded view you can use the following code to get the surrounding document:
Dim ws as New NotesUIWorkspace
Dim uidoc as NotesUIDocument
Then you could set fields on base of the currently selected document in the view e.g. in the event Onselect (new since Version 8) you could place some code like this (partly taken from Desiger help of event Onselect ):
Dim ws as New NotesUIWorkspace
Dim uidoc as NotesUIDocument
Dim lastCaretID As Variant
lastCaretID = "000"
Set uidoc = ws.CurrentDocument
Sub Onselect(Source As Notesuiview)
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Set db = session.CurrentDatabase
caretNoteID$ = Source.CaretNoteID
If lastCaretID <> caretNoteID$ Then ' we only process if the highlighted row has changed
lastCaretID = caretNoteID$
noteID$ = "NT00000" + caretNoteID$
Set doc = db.GetDocumentByID( caretNoteID$ )
Call uidoc.Document.ReplaceItemValue( "SelectedSubject", doc.GetitemValue( "Subject") )
End If
End Sub
Take care: Calling uidoc.Refresh / uidoc.Reload from within code in the embedded view context will most certainly crash your Notes- Client, so don#t do this...
As far as I know there is no easy way to do that in classic Notes. You may have to rethink your design/approach. I would use a picklist dialog box for this.
I am sure you can do that in XPages, or if this is a web application it would not be that difficult to do with Javascript/jQuery.

Set uidoc = workspace.CurrentDocument crash

I try to create pdf file with NotesDocumentCollection(a collection) or a notesuidocument
problem - When i try with a base with NotesDocumentCollection, it
works to create a pdf in the document but i can't extract them... i
can't see
problem - when i try with a base with notesuidocument : it's crash
!!
I want to use the same code with the two type of base...
This is my code :
Public Sub sauverPdfPiecesJointes
Dim s As NotesSession
Dim db As NotesDatabase
Dim colldoc As NotesDocumentCollection
Dim doc As NotesDocument
Dim resultat As String
Dim monRepertoire As Repertoire
Dim monXml As Xml
Dim fichierExiste As Integer
Dim i As Integer
Dim uidoc As NotesUIDocument
Dim workspace As New NotesUIWorkspace
Dim flagUidoc As Integer
Dim nb As String
Dim vue As NotesView
Set s = New NotesSession()
'initialisation de la variable
totalResultat = ""
Set db = s.CurrentDatabase
dbFilePath = db.FilePath
dbFileName = db.FileName
'initialisation du compteur
i = 0
flagUidoc = 0
'creation du pdf du document
Set uidoc = workspace.CurrentDocument <==== CRASH HERE
Set colldoc = db.UnprocessedDocuments
If (uidoc Is Nothing) Then
'plusieurs documents sont sélectionnés
If (colldoc.Count > 0) Then
Set doc = colldoc.GetFirstDocument
While Not doc Is Nothing
(creation du pdf....) (...)
i = i + 1
Set doc = colldoc.GetNextDocument(doc)
Wend
End If
' l'utilisateur est dans le document
Else
flagUidoc = 1
'si l'utilisateur a fait une modification
Set doc = uidoc.Document
nb = doc.Universalid
Call uidoc.Close(true)
Delete uidoc
Set doc = db.Getdocumentbyunid(nb)
(creation du pdf....) (...)
Set vue = db.Getview(nomVue)
Call vue.Refresh()
End If
I will update the question if you post more details based on this answer.
Go to your IBM_TECHNICAL_SUPPORT folder and find the latest NSD.
Open it and look for the word FATAL. This will give you the crash stack. Add that to your question and it will give more details.
To understand in more detail there is a wiki article explains how to determine crashing code (although you are pointing to it, frontEnd classes don't aways behave how you expect them).
As for NotesUIWorkspace. There were issues in earlier versions of Notes (I think R8.0, or possibly R7). The issue was if you opened a Notes client but didn't open a database before executing the code, the NotesUIWorkspace would not initialise fully. It's a edge case, so not obvious.
You can also try using other methods on the NotesUIWorkspace object before touching the document. See if it crashes as well.
Other then this, for your code to work it also needs to have a document in context in the front end. So if you have not selected a document, or have a document open then it should fail (but not crash).
You can also use the LND tool to get more details on the nature of the crash.
After analyzing your code I assume that
it is an agent
with target option "All selected documents" and
shall work on current opened document or on selected documents in view
The usual pattern for this kind of jobs is to look
first for selected documents in view with database.UnprocessedDocuments and if no documents are selected
second for opened document in UI or for marked document in view with session.DocumentContext
This way you don't need a NotesUIDocument and with following code example you have to call your pdf creation code only once:
Dim session As New NotesSession
Dim db As NotesDatabase
Dim col As NotesDocumentCollection
Dim doc As NotesDocument
Set db = session.CurrentDatabase
Set col = db.UnprocessedDocuments
If col Is Nothing Then
Set doc = session.DocumentContext
Else
Set doc = col.GetFirstDocument
End If
While Not doc Is Nothing
'
' create pdf for doc here ....
'
If col Is Nothing Then
Set doc = nothing
else
Set doc = col.GetNextDocument(doc)
End If
Wend

Lotus notes - refering to a doc. from a NotesDocumentCollection

I have a view which on top there is a button called Delete
I want to delete all the selected documents from the view; for this I used:
Dim session As New NotesSession
Dim workspace As New NotesUIWorkspace
Dim database As NotesDatabase
Dim documentCollection As NotesDocumentCollection
Set database=session.CurrentDatabase
Set documentCollection=database.UnprocessedDocuments
If documentCollection.Count=0 Then
Msgbox "No documents selected ",,"warning"
Else
userChoice=Msgbox ("Delete" & Cstr(documentCollection.Count) & " documents?",64+100, _
"Confirm...")
If userChoice=6 Then
Call documentCollection.RemoveAll(True)
Call workspace.ViewRefresh
End if
But, what if I want to delete only some docs ( from all selected docs. from view ) which have let say Value = YES where Value is a text field inside the document?
I tried declaring:
Dim ui As NotesUIDocument
Dim doc As NotesDocument
Set doc=ui.document
But I get the message: Object variable not set. So I guess I have to refer to a document using the NotesDocumentCollection? How?
Thanks for your time!
Your Error Message has nothing to do with your question... The Error Message comes from setting doc form an unitialized uidoc. You need to have a Set ui = ws.CurrentDocumentsomewhere in your code, and of course declare ws: Dim ws as New NotesUIWorkspace
But for your question you don't need an ui- document at all. To delete just some of the selected documents, you cycle through the collection and delete just the documents that match your criteria:
Dim doc as NotesDocument
Dim nextDoc as NotesDocument
Set doc = documentCollection.GetFirstDocument()
While not doc is Nothing
Set nextDoc = documentCollection.GetNextDocument(doc)
if doc.GetItemValue( "Value" )(0) = "Yes" then
call doc.Remove(True)
end if
Set doc = nextDoc
Wend
Or you reduce the collection to just contain the documents that match your criteria and then delete the whole collection:
Call documentCollection.FTSearch("[Value] = Yes",0)
Call documentCollection.RemoveAll()
But take care: The collection is reduced with a FTSearch, that might also get "Yes of course" or "Ye" depending on the setting of the FT Index of the database -> Not very reliable.
You need to loop through the documents in the document collection and then process them individually. Here's an example loop that uses your documentCollection variable:
Dim doc As NotesDocument
Set doc = documentCollection.GetFirstDocument
While Not(doc Is Nothing)
' Do stuff
' Get next document
Set doc = documentCollection.GetNextDocument(doc)
Wend

Lotus Domino cannot move subdocuments from one document to another?

Our Domino developer told us that it is "technologically impossible" to move subdocuments between documents. Is this true?
Earlier this year he wrote for us a course registration system with the following database diagram:
Now we asked him how to move waitlisted registrants from the full training sessions to those sessions that are not. He said it is impossible. He said we need to re-enter (recreate, copy and paste manually) the waitlist records because Domino cannot move attendees from one session to another.
We have over 1000 attendees in our waitlists.
Is he correct? Is this for real? We hope for a solution.
How to do it depends on the way the documents are linked. But in any case it should be possible to relink the documents using code (formula/lotusscript/java).
The help of the Lotus designer contains a lot of information about application development. Another resource is IBM developerworks
There are numerous Lotus related blogs
From the Lotus Designer help:
MakeResponse: Makes one document a response to another document. The two documents must be in the same database.
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim docA As NotesDocument
Dim docB As NotesDocument
Set db = session.CurrentDatabase
Set view = db.GetView( "All documents" )
Set docA = view.GetFirstDocument
Set docB = view.GetNextDocument( docA )
Call docB.MakeResponse( docA )
docB.Form = "Response"
Call docB.Save( True, True )
There are 2 ways that documents can be linked:
- via keys, the soft way
- hierarchically, using a document-response link (i.e. parent-child)
If there is only the logical link, using keys, you only have to adapt the key fields. If there is a "physical", document-response link, you can easily break and recreate that link. In LotusScript there is the NotesDocument.MakeResponse method to attach any document to a new parent. If both methods are used, redundant of course but practical when you need to recover some links, you need to do both changes. Usually, some key fields are repeated from parent to child
Just for testing purposes, you could try this:
- select a response document that you want to hang elsewhere
- Ctrl-X
- select the new parent document
- Ctrl-V
Do this in a test database, for the key fields won't be updated automatically. By the way: code can be written to repair the keys after pasting such a response document.
If you want to keep existing documents you could programmatically copy/duplicate them.
It's quite easy using copyAllItems method.
Look Domino help (with example) here
You could iterate documents with notesView object (getFirstDocument() / getNextDocument() methods), iterate responses on notesdocument.responses method...
Trust us, it's possible, Domino is flexible :-)
There are basically 2 ways this data is linked in the data model you describe. If the data is linked through response document hierarchies it will be slightly different from key based document structures.
Show this to your developer and, he should literally be able to plug in the code to enable the "move attendees" requirements that you're talking about.
A few things to note.
I am assuming that all the data you need to manipulate is in one database.
I am taking your diagram you've provided literally.
For key based document structures, you'll need to check the view and key values used o find attendee documents. Specifically check these 2 lines in the "MoveAttendeesKeyBased" sub:
Set vwAttendeesByCourseID = db.GetView("(LkupAllAttendeesByCourseID)")
Set dcAttendees = vwAttendeesbyCourseID.GetAllDocumentsByKey(docCourseFrom.CourseID(0), True)
The code is designed to look at a field called "CourseID", "Status" and the value of "Wait Listed" for the status value of attendees to be moved.
It took about 20 minutes to write both versions of this function.
For response based document structures
Sub MoveAttendeesResponseBased(docCourseFrom As notesDocument, docCourseTo As NotesDocument)
%REM
A simple move attendees function if the relationship between courses and attendees is based on
response document hierarchies
%END REM
On Error Goto errHandle
Dim dcAttendees As notesDocumentCollection
Dim docAttendee As notesDocument
Dim iAvailablePlaces As Integer
Dim bMoved As Boolean
If Not (docCourseFrom Is Nothing Or docCourseTo Is Nothing) Then
iAvailablePlaces = docCourseTo.availablePlaces(0)
If 0 < iAvailablePlaces Then
bMoved = False
Set dcAttendees = docCourseFrom.Responses
Set docAttendee = dcAttendees.GetFirstDocument
While Not docAttendee Is Nothing And 0 < iAvailablePlaces
If Ucase(Trim(docAttendee.Status(0)))= "WAIT LISTED" Then
Call docAttendee.MakeResponse(docCourseTo)
If docAttendee.Save(True,True) Then
iAvailablePlaces = iAvailablePlaces - 1
bMoved = True
End If
End If
Set docAttendee = dcAttendees.GetNextDocument(docAttendee)
Wend
If bMoved Then
docCourseTo.availablePlaces = iAvailablePlaces
Call docCourseTo.Save(True,False)
End If
End If
End If
Exit Sub
errHandle:
Messagebox Lsi_info(2) + " - " + Str(Err) + " : " + Error(Err) + ", at line " + Str(Erl)
Exit Sub
End Sub
For key based document structures
Sub MoveAttendeesKeyBased(docCourseFrom As notesDocument, docCourseTo As notesDocument)
%REM
A simple move attendees function if the relationship between courses and attendees uses
(non-response) key based documents
%END REM
On Error Goto errHandle
Dim session As New notesSession
Dim dcAttendees As notesDocumentCollection
Dim docAttendee As notesDocument
Dim iAvailablePlaces As Integer
Dim bMoved As Boolean
' a view that lists attendees by Course ID
Dim vwAttendeesByCourseID As notesView
Dim db As notesDatabase
If Not (docCourseFrom Is Nothing Or docCourseTo Is Nothing) Then
iAvailablePlaces = docCourseTo.availablePlaces(0)
If 0 < iAvailablePlaces Then
Set db = session.CurrentDatabase
' do a lookup of all attendees based on the CourseFrom document course id
Set vwAttendeesByCourseID = db.GetView("(LkupAllAttendeesByCourseID)")
' this is the collection of all attendees under the CourseFrom document
Set dcAttendees = vwAttendeesbyCourseID.GetAllDocumentsByKey(docCourseFrom.CourseID(0), True)
bMoved = False
Set docAttendee = dcAttendees.GetFirstDocument
' While there are attendee documents to process and there are available places to goto
While Not docAttendee Is Nothing And 0 < iAvailablePlaces
' if the attendee's status is "Wait Listed" then move them
If Ucase(Trim(docAttendee.Status(0)))= "WAIT LISTED" Then
' Update the course ID for the Attendee
docAttendee.CourseID = docCourseTo.CourseID(0)
If docAttendee.Save(True,True) Then
' decrement the available places
iAvailablePlaces = iAvailablePlaces - 1
bMoved = True
End If
End If
Set docAttendee = dcAttendees.GetNextDocument(docAttendee)
Wend
If bMoved Then
' available places may be >= 0. Just update the available places so you don't over book the course
docCourseTo.availablePlaces = iAvailablePlaces
Call docCourseTo.Save(True,False)
End If
End If
End If
Exit Sub
errHandle:
Messagebox Lsi_info(2) + " - " + Str(Err) + " : " + Error(Err) + ", at line " + Str(Erl)
Exit Sub
End Sub
Key based documents are a little more work but I think are a better structure because you can easily move documents in databases and restore from backups, copy and paste. With response documents you may have issues restoring backups becasue response documents use parent document UNID's to associate themselves to, and also if you move an attendee by accident, it would be impossible to know which course to put the attendee back onto without the original course information, thus leading you back to a key based structure for documents.(But that's just my opinion).....

Filter Process script Library

I have a form called Approver in "Approver" db.
The form has two editable text fields: Office and Group. It also has a dialog list field superior1.
The superior1 dialog list field should show the staff details filtered based on office & group:
if office = TSP & group = HR from the approver form, then shud filter the staffs based on these fields group" & "office" with the "Staff info" view of another database "TSP_Staff" and show in superior1.
But it is not getting filtered for me. :(
I am new to this tech, so I am confused and have no one to help me in this. This is the script I used:
for the superior1 field:
Sub Entering(Source As Field)
Dim s As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim uidoc As NotesUIDocument
Dim doc As Notesdocument
Dim work As New NotesUIWorkspace
Dim workspace As New NotesUIWorkspace
Dim sname As String
Dim consr As String
Dim cview As notesview
Set db = s.CurrentDatabase
Set uidoc = work.CurrentDocument
Set uidocs = workspace.currentdocument
Set cview = db.getview("(Application)")
'etype = uidoc.FieldGetText("Office")
'ftype = uidoc.FieldGetText("Group")
etype = "TSP"
ftype = "TSP1-G"
If(etype <> "" And ftype <> "") Then
Call filter
End If
Set view = db.getview("(x_search_staff)")
Set doc = view.GetDocumentByKey (uidoc.fieldgettext("Superior1"),True)
If doc Is Nothing Then
Msgbox "There is no previous transaction please select new trasaction.", 16, "Information"
Call uidoc.FieldClear("Superior1")
Call uidoc.gotofield ("Group")
Call uidoc.gotofield ("Office")
continue = False
Exit Sub
End If
Call uidoc.Refresh
End Sub
from the script library ...
Sub filter
Dim s As New notessession
Dim w As New notesuiworkspace
Dim uidoc As notesuidocument
Dim doc As notesdocument, newdoc As notesdocument, d As notesdocument, dd As notesdocument
Dim doc1 As NotesDocument, newdoc1 As NotesDocument
Dim dc As notesdocumentcollection
Dim bc As notesdocumentcollection
Dim view As notesview, v As notesview
Dim db As notesdatabase
Dim nextdoc As NotesDocument
Dim cview As notesview
Dim cnview As NotesView
Dim get_db As New notesdatabase(gsserver2, gspath2 & "Master\TSP_Staff.nsf")
Set db = s.currentdatabase
Set view = get_db.getview("(Staff Info)")
Set cview = db.getview("(x_search_staff)")
Set cnview = db.getview("(x_superior)")
Set uidoc=w.CurrentDocument
'To delet searched previous datas from form2 ----------------------------------------
Print "Please wait ..."
key = "Approver2"
Set v = db.getview("(x_delete_2)")
Set dc = v.GetAlldocumentsByKey(key,True)
'Set bc = v.GetAlldocumentsByKey(key,True)
'Call bc.RemoveAll(True)
Call dc.RemoveAll(True)
Call cview.Refresh
Call view.Refresh
Call cnview.Refresh
Call v.Refresh
'To start searching process based on Superior1 --------------------------------------
'f1= uidoc.FieldGetText("Office")
f1= uidoc.FieldGetText("Group")
'f1 = "TSP1-G"
Set dc = view.getalldocumentsbykey(f1, True)
'Set bc = view.getalldocumentsbykey(f2, True)
For b =1 To dc.count
Set doc = dc.getnthdocument(b)
Set newdoc = doc.copytodatabase(db)
'For c =1 To bc.count
'Set doc1 = bc.getnthdocument(b)
'Set newdoc1 = doc.copytodatabase(db)
If doc.form(0) = "Approver" Then
'If doc1.form(0) = "Approver" Then
newdoc.form = "Approver2"
'newdoc1.form = "Approver2"
'End If
End If
newdoc.save True, True
' Next
'newdoc.save True, True
'Next
Call w.viewrefresh
Call cview.Refresh
Call v.Refresh
Call cnview.Refresh
Call view.Refresh
Print "Process Completed....."
End Sub
if u got another way for this requirement temme in stepwise wat to do... or else... chk out ma script for errors... hope u help me :( today due date for this task...
I'm not sure how smart it is to filter the documents shown in a view by deleting documents from a database :)
My suggestion is to first post the code properly. This is simply unreadable.
How to display only subset of documents in your dialog list?
Create a hidden field on your form (you'll fill it with values you want displayed in the list using your code).
And then, on your dialog list field properties, second tab, set choices option to be "Use formula for choices" and set it to be the hidden field name.
Ask if you need more help...
Your code is very hard to follow, but if I understand your intention and parts of the filter function (does it even compile?) you could replace all of the code with this #dblookup-based formula in "use formula for choices" section of superior1 properties:
#dblookup("":"ReCache";"ServerName":"foo\Master\TSP_Staff.nsf";"(Staff Info)";Group;NameOfInterestingField);
You might want to add a #sort and/or #unique around it if the view contain duplicate values, and you might want to add the keyword [FAILSILENT] if some groups should result in an empty list.
An even simpler method could be to configure superior1 to use view dialog for choices.

Resources