To help you, I wrote a contract with functions that can return list of all addresses subscribed to a specific subscription plan (0,1,2 ....) + other functions like deleteUser(),subscribeUser() etc.
It's example of how you can do it all without for loops (you instead use mapping to remember "index")
This is a simple example where every user only has a single subscription, but it can be modified such that a single user has as many subscriptions as you wish. But I tried to keep it simple/redable so as to not overwhelm you.
Hope it helps.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract SubscriptionContract {
mapping(uint => Subscription) public subscriptionMap;
mapping(address => UserData) public userMap; //Helps to know which user is subscribed to which service
struct Subscription {
string subscriptionName; //Netflix,Amazon etc
address[] addresses;
}
struct UserData {
uint subscriptionID; //Code number for Netflix,Amazon etc
uint index; //Users location is array of addresses (So we can delete it without For loop)
}
function createSubscription(uint subscriptionID, string calldata name) public {
subscriptionMap[subscriptionID].subscriptionName = name; //Netflic,Amazon etc
}
//User subscribes himself
function subscribeUser(uint subscriptionID) public {
userMap[msg.sender].index = subscriptionMap[subscriptionID].addresses.length;
subscriptionMap[subscriptionID].addresses.push(msg.sender);
userMap[msg.sender].subscriptionID=subscriptionID;
}
//We delete specific user from subscription
function deleteUser(address userAddress) public {
//First we find his subscriptionID
uint subscriptionID = userMap[userAddress].subscriptionID;
//Next we find user's location in the array
uint index = userMap[userAddress].index;
//Now we delete the user from subscription (if it's there)
//Deleting a member in array is done by replacing it with the last member of the array
uint lastIndex= subscriptionMap[subscriptionID].addresses.length -1;
subscriptionMap[subscriptionID].addresses[index] = subscriptionMap[subscriptionID].addresses[lastIndex]; //Replacment
subscriptionMap[subscriptionID].addresses.pop(); //Removing value at lastIndex
}
function getAllSubscribers(uint subscriptionID) public view returns (address[] memory) {
return subscriptionMap[subscriptionID].addresses;
}
}
EDIT: Considering you said the first answer did not suit your needs, I just tried to fix your code (What is a bit tricky as we don't have entire contract so I have to guess some stuff)
I think your issue was mixing unit currentIndex vs unit currentId, you seem to be using both instead only one of those variables.
Below is adapted version of your code.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract AllSubscriptions {
struct Subscription {
address subscriber;
uint start;
uint nextPayment;
}
mapping(address => mapping(uint => Subscription)) public subscriptions;
uint totalSubscriptions; //Number of subscriptions
function addSubscription(uint subscriptionID, uint startDate) public {
subscriptions[msg.sender][subscriptionID].start = startDate; //Added new subscription
subscriptions[msg.sender][subscriptionID].subscriber = msg.sender; //Added new subscription
totalSubscriptions +=1;
}
function getAllsubscriptions() public view returns (Subscription[] memory) {
Subscription[] memory items = new Subscription[](totalSubscriptions);
//We asume subscriptionID's are incremental (from 0 -> totalSubscriptions)
for(uint i = 0; i < totalSubscriptions; i++) {
uint subscriptionID = i;
// pointer
Subscription storage currentSubscription = subscriptions[msg.sender][subscriptionID];
items[subscriptionID] = currentSubscription;
subscriptionID += 1;
}
return items;
}
}
EDIT2: Second version of contract (Here for simplicity I assumed every user only has a single Subscription + subscriptionID cant be Zero)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract AllSubs {
struct Subscription {
address subscriber;
uint start;
uint nextPayment;
}
mapping(address => mapping(uint => Subscription)) public subscriptions; //uint = 0 is a default value, so no subscription should have that number as its ID.
uint totalSubscriptions; //Number of subscriptions
address[] allSubcribers; //Array contaning all subscribers
uint[] subscriptionList; //This way I know who has what subscriptionID
function addSubscription(uint subscriptionID, uint startDate) public {
if (subscriptions[msg.sender][0].start == 0){
allSubcribers.push(msg.sender); //Adding address to the list if this is its first subscription
subscriptionList.push(subscriptionID);
}
subscriptions[msg.sender][subscriptionID].start = startDate; //Added new subscription startDate
subscriptions[msg.sender][subscriptionID].subscriber = msg.sender; //Added new subscription
totalSubscriptions +=1;
}
function getAllsubscriptions() public view returns (Subscription[] memory) {
Subscription[] memory items = new Subscription[](totalSubscriptions);
//We asume subscriptionID's are incremental (from 0 -> totalSubscriptions)
for(uint i = 0; i < allSubcribers.length; i++) {
address subscriberAddress = allSubcribers[i];
uint subscriptionID = subscriptionList[i];
// pointer
Subscription storage currentSubscription = subscriptions[subscriberAddress][subscriptionID];
items[i] = currentSubscription;
}
return items;
}
}