Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automating downloading of complete QSF library from Qualtrics user library #299

Open
yuvso opened this issue Dec 7, 2022 · 17 comments
Open

Comments

@yuvso
Copy link

yuvso commented Dec 7, 2022

Hi, first of all - thanks for your lovely qualtRics package. It is very useful!

I've encountered a problem, I need to download all my qualtrics surveys - data, metadata and QSF files - from my user account.

I used qualtRics to automate downloading and saving of both survey data and metadata successfully. However - I have not found a way through qualtRics script to fetch the list, and download QSF files.

Obviously this should not be a problem, as QSF are equivalent to surveyIDs and since identification and opening a connection is already happening through "fetch survey" command.

Thank you for any help!
Yuval

@yuvso yuvso changed the title downloading complete QSF library from Qualtrics user library Automating downloading of complete QSF library from Qualtrics user library Dec 7, 2022
@jmobrien
Copy link
Collaborator

jmobrien commented Dec 7, 2022

Hi @yuvso,

Question to help me figure out what you need--what do you need the QSF's for?

The function fetch_description() contains all the same content as what's in a QSF, just in a slightly different configuration. So, if you just need an archive of survey contents/configuration, or if you want to use that content information as metadata for, say, making codebooks, variable labels, or other documentation, then fetch_description() has all that you need. (I myself have done exactly that in a big project, and it worked well.)

If you need the QSF's as QSF's--for, say, other people to upload using the web interface, the qualtRics package doesn't yet have the ability to get them. That said, the API endpoint that fetch_description() uses actually can provide QSFs. For some reason, though, Qualtrics decided on this alternative format as the default, possibly because it integrates better with other tools for developing surveys directly via the API (though I'm not sure about that)

While we don't yet have the QSF option added to fetch_description(), it might be something that could be added if people want it. @juliasilge, thoughts on something like a fetch_qsf() function? Seems like it could just be an extension of the existing fetch_description() that uses the format = qsf parameter in the call, and which outputs the raw JSON for saving (rather than converting it to an R list like fetch_description() does).

@juliasilge
Copy link
Collaborator

Could this be an argument to the existing fetch_description() function itself? Maybe after the dots? The function would still return a list in both cases, but with format = "qsf" or similar it would be a slightly different list.

@jmobrien
Copy link
Collaborator

jmobrien commented Dec 7, 2022

I could see both being workable.

Possibly, yes. I think the relevant considerations are the quite different output we'd want (R list vs JSON). Also, we might want to add a few more arguments--maybe one for writing directly to a file† vs stdout, maybe also one for prettifying the JSON beforehand so it's human-readable. Definitely something that could work inside fetch_description(), still, though. I know there's some point where requiring users to know about two functions becomes more intuitive than requiring them to know two different ways to work the args in one function, but we might be in judgment-call territory on this.

†(Bringing up direct writing because writing JSON direct to file needs something like writeLines([jsonstring], con = file([filepath])), which is likely not intuitive for users only familiar with the read/write tools for tabular data.)

I actually already made a super-quick fetch_qsf() as an example, but paused it because format = "qsf" is a query parameter so I needed to finish PR #301 instead (and also because @dsen6644 needed it). If #301 can be made ready to merge I can post up the QSF PR as a draft for easier discussion.

@yuvso
Copy link
Author

yuvso commented Dec 8, 2022

Hi @yuvso,

Question to help me figure out what you need--what do you need the QSF's for?

The function fetch_description() contains all the same content as what's in a QSF, just in a slightly different configuration. So, if you just need an archive of survey contents/configuration, or if you want to use that content information as metadata for, say, making codebooks, variable labels, or other documentation, then fetch_description() has all that you need. (I myself have done exactly that in a big project, and it worked well.)

If you need the QSF's as QSF's--for, say, other people to upload using the web interface, the qualtRics package doesn't yet have the ability to get them. That said, the API endpoint that fetch_description() uses actually can provide QSFs. For some reason, though, Qualtrics decided on this alternative format as the default, possibly because it integrates better with other tools for developing surveys directly via the API (though I'm not sure about that)

While we don't yet have the QSF option added to fetch_description(), it might be something that could be added if people want it. @juliasilge, thoughts on something like a fetch_qsf() function? Seems like it could just be an extension of the existing fetch_description() that uses the format = qsf parameter in the call, and which outputs the raw JSON for saving (rather than converting it to an R list like fetch_description() does).

@yuvso yuvso closed this as completed Dec 8, 2022
@yuvso yuvso reopened this Dec 8, 2022
@yuvso
Copy link
Author

yuvso commented Dec 8, 2022

Hi @yuvso,

Question to help me figure out what you need--what do you need the QSF's for?

The function fetch_description() contains all the same content as what's in a QSF, just in a slightly different configuration. So, if you just need an archive of survey contents/configuration, or if you want to use that content information as metadata for, say, making codebooks, variable labels, or other documentation, then fetch_description() has all that you need. (I myself have done exactly that in a big project, and it worked well.)

If you need the QSF's as QSF's--for, say, other people to upload using the web interface, the qualtRics package doesn't yet have the ability to get them. That said, the API endpoint that fetch_description() uses actually can provide QSFs. For some reason, though, Qualtrics decided on this alternative format as the default, possibly because it integrates better with other tools for developing surveys directly via the API (though I'm not sure about that)

While we don't yet have the QSF option added to fetch_description(), it might be something that could be added if people want it. @juliasilge, thoughts on something like a fetch_qsf() function? Seems like it could just be an extension of the existing fetch_description() that uses the format = qsf parameter in the call, and which outputs the raw JSON for saving (rather than converting it to an R list like fetch_description() does).

Well, this is the proprietary method of Qualtrics' migration and re-installation of a specific survey. It's best way I know of, to back survey's up in most complete manner.

@jmobrien
Copy link
Collaborator

jmobrien commented Dec 8, 2022

@yuvso, thanks. That's what I assumed at a default. It does seem like something people might commonly want, and so something we should consider supporting.

I'm currently experimenting in draft #302 with how we might support getting QSFs easily through the API. The new function for that (for now, approach isn't decided) is fetch_qsf(). If you're interested in trying it out (with the understanding that it's still not officially a part of the package), the draft version can be installed with remotes::install_github("ropensci/qualtRics", ref = "0060364").

If you do try it on your use case, we'd love feedback on any issues, ideas, or suggestions that you discover. You're also welcome to submit PRs for code changes directly if that interests you.

@yuvso
Copy link
Author

yuvso commented Dec 8, 2022 via email

@juliasilge
Copy link
Collaborator

juliasilge commented Dec 8, 2022

@yuvso I would restart R, install stringr, restart R, and then try again. Make sure you are not saving your workspace in between.

@yuvso
Copy link
Author

yuvso commented Dec 8, 2022 via email

@juliasilge
Copy link
Collaborator

I typically use jsonlite::write_json().

@jmobrien
Copy link
Collaborator

jmobrien commented Dec 8, 2022

@juliasilge, weirdly enough jsonlite::write_json() actually won't write out a "json" object as JSON--it just treats it as a character vector and then writes the contents as an element in a JSON array. If you then read it back in with read_json(), you just get a string of unparsed JSON.

The only way I've figured out so far is to write the lines out manually, like below using writeLines() to a file connection:

 # Make connection to file:
  connection <-
      file(filepath)

# Write lines of JSON to file:
 writeLines(
    text =  [downloadedJSON], 
    con = connection
)

close(connection)

But, since I think you're right @yuvso to expect that most of the time people will want to save rather than work with the JSON in R , in the fetch_qsf() test function there are two arguments save and file to do this more directly (the code above is adapted from that function). Basically, this:

fetch_qsf([surveyID], save = TRUE file = "survey.qsf")

should (if everything's working) create the appropriate file called survey.qsf in your working directory.

There might be other ways to save, but I'm still learning.

If you needed to do a bunch, I suppose you could set up something with these tools using all_surveys(), purrr::map() and fetch_qsf() to do it all together.

@jmobrien
Copy link
Collaborator

jmobrien commented Dec 8, 2022

Just for fun, something like the below would, I think, save QSF's for every survey in your all_surveys() list (assuming you had permission to get that metadata for each one, so no errors):

# List all surveys:
qualtRics::all_surveys() |>
  # Create potential filenames for each combining survey id and survey name:
  dplyr::mutate(
    file = glue::glue("{surveyID} - {title}.qsf", surveyID = id, title = name)
  ) |> 
  # Take just the key parts:
  dplyr::select(surveyID = id, file) |> 
  # Cycle through list, saving each to the new filename
  purrr::pwalk(fetch_qsf, save = TRUE)

I haven't actually tested the above, because it would run hundreds of API calls for me and make tons of files. But I think it illustrates an idea of a how this might integrate qualtRics tools into an archival workflow.

@jmobrien
Copy link
Collaborator

jmobrien commented Dec 8, 2022

@juliasilge now I'm wondering whether we should have renamed the "id" column in all_surveys() output to "surveyID". If we had, its results would feed more easily into other tools in the package.

There are only two hard things in Computer Science: cache invalidation and naming things.
— Phil Karlton

@yuvso
Copy link
Author

yuvso commented Dec 9, 2022

I've run the latest, seems to be an error within glue::glue()

Error in eval(parse(text = text, keep.source = FALSE), envir) :
object '.x' not found

@jmobrien
Copy link
Collaborator

My mistake @yuvso--I restructured that right before posting it, and forgot to change those .x's and .y's to what they should be. (.x/.y is something used inside the purrr::map/walk functions, but that glue call isn't inside there anymore).

I edited the code above, and it seems to be working now. You're welcome to try it again if you like. But mainly it's still just an illustration, and/or maybe something that could go into examples/vignettes for this functionality.

@yuvso
Copy link
Author

yuvso commented Dec 13, 2022

Thanks! This look great, I've tested your latest version and it worked like a charm.

@saritpery
Copy link

This is great!
Thank you so much for adding this function.
I have an issue with some of the surveys, where a manual creation of a qsf format works great (meaning it restores when I wish), but the fetch_fsq function generated a similar qsf file, that can't be restored and generates:
Error parsing file: The file does not appear to be a valid survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants