Welcome to the LimeSurvey Community Forum

Ask the community, share ideas, and connect with other LimeSurvey users!

Edit respondent table via API / R/Limer (Add/edit respondents and/or variables)

  • socius
  • socius's Avatar Topic Author
  • Offline
  • Premium Member
  • Premium Member
More
5 years 8 months ago #170819 by socius
Hi everybody,

I have a question concerning the API and more specifically using the great R package Limer to directly connect to and change the respondent table of my surveys.

I'd like
(1) to add/delete respondents from the respondent table of a survey via API - and

(2) I'd like to be able to add variables to the respondent table and fill in values for the existing respondents (that would be just perfect - since I have a panel where I learn more and more about the respondents - e.g. their preferred day of the week to receive the invitation)

In both cases I'd like to add and/or change the entrys for a lot of respondents - so manually add them one-by-one I'd like to avoid - and I'd prefer a reproducible solution via API and Limer without uploading respondent tables etc.

So far I know that it's possible to get all the information from the participant table via the APIs "list_participants". In R with Limer this:

Code:
resp <- call_limer(method = "list_participants", 
           params = list(iSurveyID = sid))

It saves the respondent table in an object "resp" that can be worked with. This is very, very handy - but: are there also methods to write and change the respondent table from the API? And are they applicable from R with Limer?

Thanks a lot for your time!
Best, G
The topic has been locked.
  • socius
  • socius's Avatar Topic Author
  • Offline
  • Premium Member
  • Premium Member
More
5 years 8 months ago #171573 by socius
Hi!

I'm still looking for a way to read and and change token tables - maybe some of you know how to achieve this - thanks for your help on this.

An example to make it more concrete: I'd like to change the usesleft for some or all tokens of a specific survey.

To get the participant properties I use the respective method "get_participant_properties" ( api.limesurvey.org/classes/remotecontrol...rticipant_properties ). I use LS 2.6.7 LTS and the R package limer to access the API.

Code:
 
tok <- call_limer(method = "get_participants_properties", 
           params = list(iSurveyID = sid))
str(tok)
 

This gives me a data frame with tid, token, firstname, lastname, email - but no other attributes, and not "usesleft" which I'd like to change.

If I could access the "usesleft", I guess it would be possible to change this variable via "set_participant_properties" ( api.limesurvey.org/classes/remotecontrol...rticipant_properties ). Am I right?

I'd appreciate any help here - thanks a lot for your time!
Best,
G
The topic has been locked.
  • socius
  • socius's Avatar Topic Author
  • Offline
  • Premium Member
  • Premium Member
More
5 years 8 months ago #171577 by socius
Hi again,

I just saw an error in my last/above message:


It is ...
Code:
tok <- call_limer(method = "list_participants", 
           params = list(iSurveyID = sid))
str(tok)

that returns a data frame with tid, token, firstname, lastname, email - but no other attributes, and not "usesleft" which I'd like to change.


The above mentioned ...

Code:
tok <- call_limer(method = "get_participant_properties", 
           params = list(iSurveyID = sid))
str(tok)

returns NULL.

How would I have to change the latter code to get other/all the attributes in the token table?

Sorry for that mistake!

Best,
G
The topic has been locked.
  • socius
  • socius's Avatar Topic Author
  • Offline
  • Premium Member
  • Premium Member
More
5 years 8 months ago - 5 years 8 months ago #171736 by socius
Hi everbody,

I think I'm making slight progress in this. I still want to get and set the usesleft attribute in the tokentable (ideally for multiple respondents at once depending on other attributes - but first things first). I use R with the handy limer package (s. github.com/cloudyr/limer )

Some methods to get (and set) participant properties.
Code:
### List participants with method list_participants via limer

tok <- call_limer(method = "list_participants", 
           params = list(iSurveyID = sid))
str(tok)

This returns a data frame with the basic information on the respondents (here: shortened and anonymized):
Code:
'data.frame':  10 obs. of  3 variables:
 $ tid             : chr  "1" "2" "3" "4" ...
 $ token           : chr  "token1" "token2" "token3"...
 $ participant_info:'data.frame':  10 obs. of  3 variables:
  ..$ firstname: chr  "" "" "" "" ...
  ..$ lastname : chr  "" "" "" "" ...
  ..$ email    : chr  "email1@email.com" "email2@email.com" "email3@email.com ...


There is another function in limer, a wrapping the method get_participants() from the remote:
Code:
### Function get_participants() from limer
#https://github.com/cloudyr/limer/blob/7c10cc62f703d03bcac23fb444ebd39cf5d0e2b0/R/get_participants.R

attr <- c('email', 'usesleft')  # select some attributes.

tok <- get_participants(sid, iStart=0, iLimit=10, bUnused=FALSE, aAttributes=attr)
 
str(tok)

This returns the information as above, but this time with the usesleft for each participant as a column.
Code:
'data.frame':  10 obs. of  4 variables:
 $ tid             : chr  "1" "2" "3" "4" ...
 $ token           : chr  "token1" "token2" "token3" ...
 $ participant_info:'data.frame':  10 obs. of  3 variables:
  ..$ firstname: chr  "" "" "" "" ...
  ..$ lastname : chr  "" "" "" "" ...
  ..$ email    : chr  "mail1@mail.com" "mail2@mail.com" "mail3@mail.com"  ...
 $ usesleft        : chr  "1" "1" "1" "1" ...

You can easily extract the vector of usesleft by
Code:
tok$usesleft  # vector of usesleft

and get
Code:
[1] "1" "1" "1" "1" "1" "1" "1" "1" "1" "1"


I figured out how to get the participant information for single participants:
Code:
### Method get_participant_properties (via limer)
# https://api.limesurvey.org/classes/remotecontrol_handle.html#method_get_participant_properties

attr <- c("tid", "email", "token", 'usesleft', 'attribute_1')
 
tok <- call_limer(method = "get_participant_properties", 
           params = list(iSurveyID = sid, 
                         tokenid = 1,
                         aTokenProperties = attr))
str(tok)

This returns:
Code:
List of 4
 $ tid     : chr "1"
 $ email   : chr "email1@email.com"
 $ token   : chr "token1"
 $ usesleft: chr1


Now that this works my questions are:

(1) How to get attributes for multiple participants at once (i.e. vectorized, e.g. tokenid = 1:100)?

(2) How to SET attributes for one participant?

This should work with the set_participant_properties - but how?
Code:
# https://api.limesurvey.org/classes/remotecontrol_handle.html#method_set_participant_properties
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         tokenid = 1,
                         aTokenProperties = "usesleft",
                         aTokenData = ?????))

And if that is clear:

(3) How to SET attributes for multiple participants at once? (If possible also vectorized, not in a loop)


Thanks for your time and help!
Best, G
Last edit: 5 years 8 months ago by socius. Reason: Formatting, Shortening
The topic has been locked.
  • DenisChenu
  • DenisChenu's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
5 years 8 months ago - 5 years 8 months ago #171742 by DenisChenu
If i read API doc :

$aTokenQueryProperties array|integer of participant properties used to query the participant, or the token id as an integer

$aTokenData array Data to change


Then for example
Code:
$aTokenQueryProperties = [useLeft=>1]
$aTokenData = [useLeft=>2]
But need fix syntax here …

Maybe
Code:
aTokenProperties = list(useLeft=1),
aTokenData =  list(useLeft=2),

Assistance on LimeSurvey forum and LimeSurvey core development are on my free time.
I'm not a LimeSurvey GmbH member, professional service on demand , plugin development .
I don't answer to private message.
Last edit: 5 years 8 months ago by DenisChenu.
The following user(s) said Thank You: socius
The topic has been locked.
  • socius
  • socius's Avatar Topic Author
  • Offline
  • Premium Member
  • Premium Member
More
5 years 8 months ago #171773 by socius
Hi!

Thanks @Denis for your response and the hint! I tried and tried - and making aTokenData a list worked!


This code changes the usesleft for tokenid = 1 to usesleft = 2:
Code:
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         tokenid = 1,
                         aTokenData = list(usesleft = "2")))
}


Now to change multiple token at once I could use a loop
Code:
# Which tokens to change?
id.select <- 1:100
 
# A Loop to apply these changes sequentially
for(i in id.select){
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         tokenid = i,
                         aTokenData = list(usesleft = "2")))
}

This code works but the execution takes some time - in my case around a minute for 100 participants. Is there another way to access the participant properties for all participants at once? I do not see this in the API (did I miss something?), but I guess directly reading/writing the token table in the database could be an option - R has functions for that, but is that a good idea or something to avoid?


Thanks a lot again!
Best,
G
The topic has been locked.
  • DenisChenu
  • DenisChenu's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
5 years 8 months ago #171777 by DenisChenu
Hi,

With a loop on tokenid : you make 100 call to a remote server …

But in aTokenProperties list : maybe you can select user with some condition ? Some attribute ? For example attribute_1 = 'groupWhoNeedMore' , or did you try with list(useLeft=1) ?

Assistance on LimeSurvey forum and LimeSurvey core development are on my free time.
I'm not a LimeSurvey GmbH member, professional service on demand , plugin development .
I don't answer to private message.
The following user(s) said Thank You: socius
The topic has been locked.
  • socius
  • socius's Avatar Topic Author
  • Offline
  • Premium Member
  • Premium Member
More
5 years 7 months ago #171934 by socius
Hi!

thanks a lot - and sorry for my late response!

I tried to change the usesleft attribute for all respondents from "1" to "2" by
Code:
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list(usesleft = "1"),
                         aTokenData = list(usesleft = "2")))

But: this only changes usesleft for the respondet with tid = 1.


If I change
Code:
aTokenQueryProperties = list(usesleft = "1")
to
Code:
aTokenQueryProperties = list(usesleft = "2")

then its the TokenData from the respondent with tid = 2 that gets changed. So it seems that the attribute in the query gets ignored and the number is taken as tokenid... Hm.

How would I have to enter the attribute to the query?

Actually it should be something like

usesleft == "1" instead of usesleft = "1"

but when I enter
Code:
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list(usesleft == "1"),
                         aTokenData = list(usesleft = "2")))

the error message is "Object 'usesleft' not found"

Hm. Any ideas what I could enter here?


Thanks for your time!
Best, G
The topic has been locked.
  • DenisChenu
  • DenisChenu's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
5 years 7 months ago #171936 by DenisChenu
Looking at code : github.com/LimeSurvey/LimeSurvey/blob/ff...rol_handle.php#L1836 : we do a search by attributes. Then if you find a way to send an array for aTokenQueryProperties then it must work.
Except if you are on an old version …

Assistance on LimeSurvey forum and LimeSurvey core development are on my free time.
I'm not a LimeSurvey GmbH member, professional service on demand , plugin development .
I don't answer to private message.
The topic has been locked.
  • socius
  • socius's Avatar Topic Author
  • Offline
  • Premium Member
  • Premium Member
More
5 years 7 months ago #171945 by socius
Hi!

Thanks! - I further tried - but I did not find a solution yet :-(

Sending an array via R/limer partially works:
aTokenData is a list in R - this works for setting the usesleft.
As I understand it doing the same with TokenQueryProperties should work to select the participants where an attribute should be set. In my case I want to set usesleft for all participants where usesleft = 1 to usesleft = 2, i.e. all these participants should be able to submit the survey twice. But: this does not work as expected.

This is what I tried (s. below) - it seems that the content of TokenQueryProperties gets ignored and any number in this array is uses as tid.

I use LS 2.6.7 LTS. How do I find the version of the API?

Any idea what's going wrong here with sending the array for the aTokenQueryProperties or how to send this correctly to the API?

Thanks a lot for your time!
Best, G

Code:
# Changes participant with tid = 1 to usesleft = 2:
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list(usesleft = "1"),
                         aTokenData = list(usesleft = "2")))
 
# Same as above, despite naming the aTokeQueryProperties "foo":
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list(foo = "1"),
                         aTokenData = list(usesleft = "2")))
 
# Changes participant with tid = 3 to usesleft = 2:
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list(usesleft = "1"),
                         aTokenData = list(usesleft = "2")))
 
# Despite tid = "4" changes participant with tid = 1 to usesleft = 2:
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list(tid = "4", usesleft = "1"),
                         aTokenData = list(usesleft = "2")))
 
# I tried to set all participants with language the same language (here "de" for German) to usesleft = 2, but this returns
# $status
# [1] "Error: Invalid tokenid"
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list(language = "de"),
                         aTokenData = list(usesleft = "2")))
 
# Returns:
# $status
# [1] "Error: Invalid tokenid"
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list("usesleft = 1"),
                         aTokenData = list(usesleft = "2")))
 
# Returns same as above:
call_limer(method = "set_participant_properties", 
           params = list(iSurveyID = sid, 
                         aTokenQueryProperties = list("usesleft = '1'"),
                         aTokenData = list(usesleft = "2")))
The topic has been locked.
  • DenisChenu
  • DenisChenu's Avatar
  • Offline
  • LimeSurvey Community Team
  • LimeSurvey Community Team
More
5 years 7 months ago #171954 by DenisChenu
Oups …
github.com/LimeSurvey/LimeSurvey/blob/ff...rol_handle.php#L1834

And a findByAttribute, not a findAllByAttribute

1. There are an issue : you must receive “Error: More than 1 result was found based on your attributes.”
2. Make a feature request to allow multiple update. It's a restriction here
3. Alternative solutiuon : create your own function in plugin : see gitlab.com/SondagesPro/coreAndTools/extendRemoteControl for a simple example to do this.

Assistance on LimeSurvey forum and LimeSurvey core development are on my free time.
I'm not a LimeSurvey GmbH member, professional service on demand , plugin development .
I don't answer to private message.
The following user(s) said Thank You: socius
The topic has been locked.

Lime-years ahead

Online-surveys for every purse and purpose