Home / Blog / From References to Embedded Container Data

From References to Embedded Container Data

FileMaker 13 introduces a new function that gives us some 30 different attributes about the data we store in a container field: GetContainerAttribute().

One of those attributes is the name of the file that we can ask for like this:

  GetContainerAttribute ( theContainer ; "filename" )

And another attribute is to see whether the file was inserted as a reference only.

  GetContainerAttribute ( theContainer ; "storageType" )

The response will be either:

  • Embedded
  • External (Secure),
  • External (Open)
  • File Reference
  • Text

“Text” is when you get when the container’s content is not a file but some text that was inserted or pasted into the container field.

“External” indicates that the container field is set up for the “Remote Container” functionality.

Before FileMaker 12, when we wanted to keep the size of the FileMaker file down the only option was to store container data by reference only.  That way the files were not stored in the file.  The huge downside of that was that the path to the container files had to be the accessible from each client through OS-level file sharing.  That setup was not always trivial, especially in mixed Windows/Mac environment.  Backups were also complex since FileMaker Server only backed up the FileMaker file and not the referenced data.

That problem was solved in FileMaker 12 with Remote Containers.  Through that feature FileMaker kept the container data outside of the FileMaker file but still managed backups and access to those files so that it worked from all clients without the need for fragile OS-level sharing.

But… there was one big caveat: the remote container folder had to be on the same drive as the FileMaker file, you could not choose your own location when you hosted the file on FileMaker Server.

Now with FileMaker 13, that issue has been solved and you can specify your own folder where that container data will be stored.

So what do you do if you have a solution that currently uses a lot of referenced container data and you want to switch over to the improved Remote Container functionality? Your only option really is to re-insert the referenced file as en embedded file.  If the container field is set up for Remote storage, FileMaker will take care of that when you insert the data.

Fortunately, this does not have to be a manual process.  Using the new attributes we can get from a container it is very easy to script it.  Below is an example of how.

First of all, I’ve created custom functions for all 30 of the different attributes you can ask about a container:

Attribute Custom Function

So instead of doing this (and having to remember the name of the attribute):

  GetContainerAttribute ( ContainerData::myContainer ; "storagetype" )

I can simply do this:

  CONTAINER_storageType ( ContainerData::myContainer )

On to the script:

  1. The first thing we do is to check if the container data is stored as a reference.  If not then there is nothing to do.
  2. If the container file is a reference, we ask for its name and also determine the file type (image, movie, file,…).
  3. When we have all the info we need, we export the referenced file to a temporary folder (FileMaker creates that folder for the duration of the script and then cleans up after itself when the script ends).
  4. After extracting the file we empty out the container.
  5. Then, re-insert the file from the temporary folder.  This is where we need the file type so that we can call the proper “Insert” script step.

And we’re done.

Here is a screenshot of the container and its info before running the script:

Container Before Running Script

And after running the script:

Container After Running Script

Get the Demo

To try it out, manually insert a file into the container and make sure to set the “by reference” toggle:

Manually Insert a File into Container

Happy New Year!

#
Allow User Abort [Off]
Set Error Capture [On]
#
#
Set Variable [$tempPath; Value:Get ( TemporaryPath )]
#
#  check if the container is by reference
If [_CONTAINER_storageType ( ContainerData::myContainer ) = _CONTAINER_STORAGE_FILEREFERENCE]
  #
  #  it is, do an export field contents and then insert it again
  #  get the file name
  Set Variable [$containerAsText; Value:ContainerData::myContainer]
  Set Variable [$fileName; Value:_CONTAINER_file_name ( ContainerData::myContainer )]
  #
  #  figure out what file type it is
  Set Variable [$type; Value:LeftWords( $containerAsText ; 1 )]
  If [Right( $fileName ; 4 ) = ".pdf" and $type <> "PDF"]
    Set Variable [$type; Value:"PDF"]
  Else If [$type = "size"]
    #  probably an image, the path is on the 2nd line, first line is the size
    Set Variable [$type; Value:LeftWords( GetValue( $containerAsText ; 2 ) ; 1 )]
  End If
  #
  #  construct the temp path and file name
  Set Variable [$temp; Value:"file:" & $tempPath & $fileName]
  #
  #  export
  Export Field Contents [ContainerData::myContainer; "$temp"]
  #
  #  delete the container and commit
  Set Field [ContainerData::myContainer[]; ""]
  Commit Records/Requests [Skip data entry validation]
  #
  #  now get the container back
  Go to Field [Select/perform; ContainerData::myContainer]
  If [$type = "image"]
    Set Variable [$temp; Value:Substitute ( $temp ; "file:/" ; "image:/" )]
    Insert Picture [$temp]

  Else If [$type = "PDF"]
    Set Variable [$temp; Value:Substitute ( $temp ; "file:/" ; "image:/" )]
    Insert PDF [$temp]

  Else If [$type = "movie"]
    Set Variable [$temp; Value:Substitute ( $temp ; "file:/" ; "movie:/" )]
    Insert Audio/Video [$temp]

  Else
    Insert File [ContainerData::myContainer[]]
  End If
  #
  Commit Records/Requests [Skip data entry validation]
#
End If

18 thoughts on “From References to Embedded Container Data”

  1. Hi Wim,

    I would like to backup the external container. Will I cause harm to the database as a whole or the contents of the external container if I use a third party backup solution to capture the external container? Thanks for any help.

    -L

  2. Hi Lorenzo,

    There is a big risk there.  The external container data really needs to be treated as any other live FileMaker file; that means no OS-level sharing, no external backups,…

    Since that data gets backed up properly when FileMaker Server runs a backup schedule, you can use an external backup program that targets those FMS backups.  Provided you time it so that the external backup application does not try to grab files as they are actively being backed up.

  3. Christian Sodemann

    Neat and useful example 🙂

    I’ve noticed that:

    GetValue ( Table::someContainer ; 2 )

    returns the filename of a previously reference file. This may be passed directly to e.g.:

    InsertPDF

    on an interactive container field, thus saving the export.

    CHS

    1. Hi Jenn,
      I would have to see some screenshots or some data to see what is going on. Feel free to post to FMforums.com or the FileMaker Community forum.

    1. Hi Marty,

      It should work just fine on Windows – just retested with FMPA15v2 on Windows 10 with a picture and a regular file. What is your content type?

  4. I just took an app from FM12 to FM15. Had filenames of referenced files in the records. I made a new container field with OPEN STORAGE, ran an insert script like yours above. My file size blew up. My storage type attribute says “External (Open)”. It did store the files in the directory structure I specified, but it is apparently also embedding. Also, I see title of your article is “…to embedded”. Am I misunderstanding? I want external storage…not embedded. What might I be doing wrong?
    –Thanks for your article; I’m almost there…

    1. Hi Carol, the technique and script used for the article does indeed aim to “embed” the file in the sense of not only storing the reference to the file but the file itself. Depending on whether the container in FM is set to use remote container (RC) storage or not, the embedding will store that file internally or in the RC folder. I would have to see your file to help troubleshoot. Feel free to post on https://community.filemaker.com.

  5. It is a great article but I cannot get storageType with either method, I only get a “?” in the field. I used these methods with my container field named “_f_SiteMap”:
    GetContainerAttribute ( _f_SiteMap ; “storagetype” )
    CONTAINER_storageType ( _f_SiteMap )
    Am I missing something?

  6. Hi Wim,
    My database has grown to about 50GB, simply because i do store 4 images for each record.
    1. field image
    2. context image
    3. lab image
    4. prep image.
    Browsing these records has become an issue.
    I need to to reference these images and store them externally to reduce the size. I need the external storage file to have subfolders as per the 4 image sets. Help me achieve that. Thanks

    1. Derek Vanderby (our business manager) will contact you about this. There are a few options here. The relatively easy one is to start using remote container storage so that the main file remains lean. The other option is to forgo regular FM containers and use an external document storage; we recommend AWS S3.
      The performance while browsing is something we’d have to look at, that’s mainly a factor of how the solution is designed.

Leave a Comment

Your email address will not be published. Required fields are marked *