0

need help on importing a .csv into two related tables (scripting help?)

I have a ninox.com database with two working tables: Contacts (to track association members) and Events (to track events to which those members are invited). The goal is to import members' attendance after each event, via .csv import. Tables Contacts and Events  are correctly linked via a third table called RSVP. I have imported an updated .csv file to a temporary table called StagingImport (a Nioxus video suggested that approach, with a script to update the actual records from here). The first column in the table attached here shows the fields in StagingImports and their field names. The second column shows the fields that need to be updated in the Contacts table and their field names (some are slighly different). The third column shows the fields that need to be updated in Events, and their field names. When I started looking at Ninox's scripting docs I realized I was in over my head. I tried asking ChatGPT (yeah, I know) for a script for a "Process the CSV Import" Button, and needless to say it errors out. The attached doc contains the label info for each table and (on page 2) the script suggested by ChatGPT. I'd appreciate any help you can offer either in correcting the script, or if there's a better (simpler) approach.

62 replies

null
    • szormpas
    • 3 days ago
    • Reported - view

     Hi,

    You can try the following code inside a button. If it works, we can optimize it further.

    do as server
    let x := select Contacts;
    let y := select Events;
    let z := select RSVP;
    for i in select StagingImport do
        let c := if contains(x.Email, i.Email) then
                    first(x[Email = i.Email])
                    else
                        create Contacts.(
                            Email := i.Email;
                            Lastname := i.'Last name';
                            Firstname := i.'First name';
                            'Mobile Phone' := i.'Mobile number';
                            Zip := i.Zip)
                        end;
        let e := if contains(y.'Event ID', i.'Event ID') then
                    first(y['Event ID' = i.'Event ID'])
                    else
                        create Events.(
                            'Event ID' := i.'Event ID';
                            'Event Name' := i.'Event name';
                            'Event Type' := i.'Event type';
                            'Date / Time' := i.'Event Start Date')
                        end;
        if count(z[Attended = i.Attended and Contacts = number(c.Id) and Events = number(e.Id)]) = 0 then
            create RSVP.(
                Contacts := number(c.Id);
                Events := number(e.Id);
                Attended := i.Attended);
        end;
    end;
    end
    
      • Dave_Airel
      • 3 days ago
      • Reported - view

       Good to know ... thanks

    • szormpas
    • 3 days ago
    • Reported - view

     Can you make a last effort to try the following script?

    do as server
      let x := select Contacts;
      let y := select Events;
      let z := select RSVP;
      for i in select StagingImport do
          let c := if contains(x.Email, i.Email) then
                       first(x[Email = i.Email])
                   else
                       create Contacts.(
                           Email := i.Email;
                           Lastname := i.'Last name';
                           Firstname := i.'First name';
                           'Mobile Phone' := i.'Mobile number';
                           Zip := i.Zip)
                   end;
          let e := if contains(y.'Event ID', i.'Event ID') then
                       first(y['Event ID' = i.'Event ID'])
                   else
                       let w := create Events.(
                           'Event ID' := i.'Event ID';
                           'Event Name' := i.'Event name';
                           'Event Type' := i.'Event type';
                           'Date / Time' := i.'Event Start Date');
                       y := array(y,w);
                        w
                   end;
           if count(z[Attended = i.Attended and Contacts = number(c.Id) and Events = number(e.Id)]) = 0 then
                       create RSVP.(
                           Contacts := number(c.Id);
                           Events := number(e.Id);
                           Attended := i.Attended);
           end;
      end;
      delete select StagingImport;
    end
    
      • Dave_Airel
      • 3 days ago
      • Reported - view

       Error on

        y := array(y,w);
                          w
      
      (what's the "W" here?)
      Screenshot 2025-06-01 at 11.07.58AM
      • Dave_Airel
      • 3 days ago
      • Reported - view
      • Dave_Airel
      • 3 days ago
      • Reported - view

       When I remove the y := line and the stray "w" below it the script runs but same problems as before.

      And the RSVP table contains updated Contact info but the Event isn't linking to it. See attached after this second try. The blanks are the imported events (the other one is a test event i entered manually)

      Screenshot 2025-06-01 at 11.13.33AM

    • Fred
    • 3 days ago
    • Reported - view

    On a side note, if you are on a Mac you can use the MacOS app to download copies of your DB regardless of the level of your subscription.

      • Dave_Airel
      • 3 days ago
      • Reported - view

       Really? I do have the Mac app, managing another (totally) unrelated database. Can I download this one (ESI) while keeping my other one (Macum Creek Concerts) active & not screwing either up? Can you point me at instructions?

      • Dave_Airel
      • 3 days ago
      • Reported - view

       FWIW each of these is 'owned' by different email addresses (same human name) if that makes a difference.

      • Fred
      • 3 days ago
      • Reported - view

      In the upper right hand corner of the app is where you login to your Ninox cloud account.

      1. Switch to your cloud workspace.
      2. Open the desired DB
      3. Make sure to select the DB name in the upper left corner (this is by default, but if you have the openTable() command then it won't)
      4. Open the Table menu and select Export Data...
      5. Click on the Ninox text
      6. Click on Save As button
      7. the follow the typical save procedure.

      Now you have a downloaded DB.

      • Dave_Airel
      • 3 days ago
      • Reported - view

       Well, I have the online db open in my Mac app, but when I get to step 4, and select Export Data in the Table menu, nothing happens. You didn't mean "Database/Archive", did you?

      • Fred
      • 3 days ago
      • Reported - view

      Did you select the DB name?

      • Dave_Airel
      • 3 days ago
      • Reported - view

        OK, success. Attached is a copy for the ESI database (exported from my Macbook app) - it has only 2 contacts, 1 event (all imports have been deleted from all tables). Sotorios' latest script is attached to the button, which will appear on the form once data exists in the StagingImport table. When I just ran the import prior to clearing stuff out, the script runs error-free and the StagingImports table is cleared after the script runs. Two issues:

      - Events were created for every entry in the .csv, but not linked to the contacts who attended

      - The Attended field is created in the RSVP table but not being populated

      Database is attached and the test .csv I've been using (entries) are attached.

      Fingers crossed -

      ESI 250601 0146pm DA.ninoxtest import 4 records

    • Dave_Airel
    • 3 days ago
    • Reported - view

    I'm going to have to log off for awhile, will check back later for updates. Thanks for the support so far - fingers crossed we're close.

    • szormpas
    • 3 days ago
    • Reported - view

     Hi, 

    I forgot to put the "w" variable in brackets []. Here's the updated script, let's hope it works!

    do as server
      let x := select Contacts;
      let y := select Events;
      let z := select RSVP;
      for i in select StagingImport do
          let c := if contains(x.Email, i.Email) then
                       first(x[Email = i.Email])
                   else
                       create Contacts.(
                           Email := i.Email;
                           Lastname := i.'Last name';
                           Firstname := i.'First name';
                           'Mobile Phone' := i.'Mobile number';
                           Zip := i.Zip)
                   end;
          let e := if contains(y.'Event ID', i.'Event ID') then
                       first(y['Event ID' = i.'Event ID'])
                   else
                       let w := create Events.(
                           'Event ID' := i.'Event ID';
                           'Event Name' := i.'Event name';
                           'Event Type' := i.'Event type';
                           'Date / Time' := i.'Event Start Date');
                       y := array(y,[w]);
                        w
                   end;
           if count(z[Attended = i.Attended and Contacts = number(c.Id) and Events = number(e.Id)]) = 0 then
                       create RSVP.(
                           Contacts := number(c.Id);
                           Events := number(e.Id);
                           Attended := i.Attended);
           end;
      end;
      delete select StagingImport;
    end
    
    • szormpas
    • 3 days ago
    • Reported - view

    I think we're getting there. The issue came up because the 'select' statement returns 'nid', but the 'create' statement returns 'rid'. Here's a script you can try out.

    do as server
        let x := (select Contacts);
        let y := (select Events);
        let z := (select RSVP);
        for i in select StagingImport do
            let c := if contains(x.Email, i.Email) then
                    first(x[Email = i.Email])
                else
                    (create Contacts).(
                        Email := i.Email;
                        Lastname := i.'Last name';
                        Firstname := i.'First name';
                        'Mobile Phone' := i.'Mobile number';
                        Zip := i.Zip
                    )
                end;
            let e := if contains(y.'Event ID', i.'Event ID') then
                    first(y['Event ID' = i.'Event ID'])
                else
                    let w := (create Events);
                    w.(
                        'Event ID' := i.'Event ID';
                        'Event Name' := i.'Event name';
                        'Event Type' := i.'Event type';
                        'Date / Time' := i.'Event Start Date'
                    );
                    y := array(y, [w.Id]);
                    w.Id
                end;
            if count(z[Attended = i.Attended and Contacts = number(c.Id) and Events = number(e.Id)]) = 0 then
                (create RSVP).(
                    Contacts := number(c.Id);
                    Events := number(e.Id);
                    Attended := i.Attended
                )
            end
        end;
        delete (select StagingImport)
    end
    
      • Dave_Airel
      • 3 days ago
      • Reported - view

       Script ran.

       

      Events were created 4x, once per line in .csv

      Events table shows 4 events, none linked to a contact.

       

       

      Contact table shows event linked to one contact, dave@airel.org.

    • szormpas
    • 3 days ago
    • Reported - view

     

    We should use the same logic in the Contacts table. If a new contact attends multiple events in the .csv file, only one new record should be created in the Contacts Table. I updated the script and made the names a bit more descriptive.

    do as server
        let allContacts := (select Contacts);
        let allEvents := (select Events);
        let allRSVP := (select RSVP);
        for i in select StagingImport do
            let contact := if contains(allContacts.Email, i.Email) then
                    first(allContacts[Email = i.Email])
                else
                    let newContact := (create Contacts);
                    newContact.(
                        Email := i.Email;
                        Lastname := i.'Last name';
                        Firstname := i.'First name';
                        'Mobile Phone' := i.'Mobile number';
                        Zip := i.Zip
                    );
                    allContacts := array(allContacts, [newContact.Id]);
                    newContact.Id
                end;
            let event := if contains(allEvents.'Event ID', i.'Event ID') then
                    first(allEvents['Event ID' = i.'Event ID'])
                else
                    let newEvent := (create Events);
                    newEvent.(
                        'Event ID' := i.'Event ID';
                        'Event Name' := i.'Event name';
                        'Event Type' := i.'Event type';
                        'Date / Time' := i.'Event Start Date'
                    );
                    allEvents := array(allEvents, [newEvent.Id]);
                    newEvent.Id
                end;
            if count(allRSVP[Attended = i.Attended and Contacts = number(contact.Id) and Events = number(event.Id)]) = 0 then
                (create RSVP).(
                    Contacts := number(contact.Id);
                    Events := number(event.Id);
                    Attended := i.Attended
                )
            end
        end;
        delete (select StagingImport)
    end
    

     

    I've attached my demo database where I did all the testing. I'm eager to hear the results from your database. Are you having any other problems?

      • Dave_Airel
      • 3 days ago
      • Reported - view

       You're correct. A contact should be updated if it's in the .csv file and the contacts table, and created (one time) if it's not. A contact will only be in .csv once, but will appear in multiple .csvs.
      An event will be in every row of a .csv. If the event already exists in the event table, it should updated and contacts linked to it. If it doesn't (the likely case) it should be created (once), and contacts linked to it.
      I'll try the new script now, let me clear out the last import and try it. Stand by---

      • Dave_Airel
      • 3 days ago
      • Reported - view

       Progress.

      Events and contacts appear to be linked correctly.

      But events are still being created for every line in the .csv.

    • szormpas
    • 3 days ago
    • Reported - view

     We made it!

    The issue in your database came up because the 'Event ID' field in the StagingImport table was set to number data type. So, I changed it to a text field type.

    Everything seems to be working as expected now. Are you happy with the final result?

    Today, I learned how to add a newly created record to an array of selected records using code. I have to thank    for his helpful contribution.

    I've attached the updated version of your database.

    Best wishes

      • Dave_Airel
      • 3 days ago
      • Reported - view

       So, I just changed the Event ID field in the StagingImports table to a text field, and now the existing script has a bunch of errors. Did you update the script? If so can you post it here? I'd like to get the existing online database working rather than trying to figure out how to use the full DB you posted (I have no idea how to do that). Here's a screenshot of the errors in the last script with the text Event ID in the StagingImports table.

      • szormpas
      • 3 days ago
      • Reported - view

        copy-paste the following script:

      do as server
          let allContacts := (select Contacts);
          let allEvents := (select Events);
          let allRSVP := (select RSVP);
          for i in select StagingImport do
              let contact := if contains(allContacts.Email, i.Email) then
                      first(allContacts[Email = i.Email])
                  else
                      let newContact := (create Contacts);
                      newContact.(
                          Email := i.Email;
                          Lastname := i.'Last name';
                          Firstname := i.'First name';
                          'Mobile Phone' := i.'Mobile number';
                          Zip := i.Zip
                      );
                      allContacts := array(allContacts, [newContact.Id]);
                      newContact.Id
                  end;
              let event := if contains(allEvents.'Event ID', i.'Event ID') then
                      first(allEvents['Event ID' = i.'Event ID'])
                  else
                      let newEvent := (create Events);
                      newEvent.(
                          'Event ID' := i.'Event ID';
                          'Event Name' := i.'Event name';
                          'Event Type' := i.'Event type';
                          'Date / Time' := i.'Event Start Date'
                      );
                      allEvents := array(allEvents, [newEvent.Id]);
                      newEvent.Id
                  end;
              if count(allRSVP[Attended = i.Attended and Contacts = number(contact.Id) and Events = number(event.Id)]) = 0 then
                  (create RSVP).(
                      Contacts := number(contact.Id);
                      Events := number(event.Id);
                      Attended := i.Attended
                  )
              end
          end;
          delete (select StagingImport)
      end
      
      • Dave_Airel
      • 3 days ago
      • Reported - view

       Aargh. Run-time errors.

      • Dave_Airel
      • 3 days ago
      • Reported - view

       No errors showing up in the script editor though. ??

      • Dave_Airel
      • 3 days ago
      • Reported - view

       also just noticed when I'm in edit mode there's an exclamation point on StagingImport. Only in edit mode. And I confirmed I changed Event ID to a text field in StagingImport

      .

Content aside

  • Status Answered
  • 2 days agoLast active
  • 62Replies
  • 88Views
  • 4 Following