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)

More
8 years 2 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.
More
8 years 1 month 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.
More
8 years 1 month 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.
More
8 years 1 month ago - 8 years 1 month 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: chr “1”


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: 8 years 1 month ago by socius. Reason: Formatting, Shortening
The topic has been locked.
More
8 years 1 month ago - 8 years 1 month 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 support - Plugins, theme and development .
I don't answer to private message.
Last edit: 8 years 1 month ago by DenisChenu.
The following user(s) said Thank You: socius
The topic has been locked.
More
8 years 1 month 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.
More
8 years 1 month 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 support - Plugins, theme and development .
I don't answer to private message.
The following user(s) said Thank You: socius
The topic has been locked.
More
8 years 1 month 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.
More
8 years 1 month 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 support - Plugins, theme and development .
I don't answer to private message.
The topic has been locked.
More
8 years 1 month 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.
More
8 years 1 month 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 support - Plugins, theme and development .
I don't answer to private message.
The following user(s) said Thank You: socius
The topic has been locked.
Moderators: tpartnerholch

Lime-years ahead

Online-surveys for every purse and purpose