Filebase icon indicating copy to clipboard operation
Filebase copied to clipboard

Query on nested Arrays

Open klopez0017 opened this issue 5 years ago • 4 comments

Hi, I have this saved database with me in this format. As you can see accounts have multiple array elements containing accID, server, expiry, editable, payment, etc.. Whenever I try to use query it gives me no results. Is nested multi array supported at the moment?

$query5 = $db_List->query()->where('accounts.accID', '=', '123')->results();
echo var_dump($query5);
{
    "__created_at": 1541705828,
    "__updated_at": 1541706169,
    "data": {
        "accounts": [
            {
                "accID": "123",
                "server": "TEST",
                "expiry": 100,
                "editable": 200,
                "payment": "x",
                "parent_payment": "y",
                "notes": "z"
            },
            {
                "accID": "456",
                "server": "TEST",
                "expiry": 100,
                "editable": 200,
                "payment": "-",
                "parent_payment": "-",
                "notes": "Coco"
            }
        ],
        "username": "TEST",
        "password": "HASH",
        "email": "[email protected]",
        "blocked": false
    }
}

klopez0017 avatar Nov 11 '18 18:11 klopez0017

Hi @klopez0017

They should be designed that way as the docs state the examples of:

// You can also use `.` dot delimiter to use on nested keys
$users = $db->query()->where('status.language.english','=','blocked')->results();

What is the response you are receiving? I will take a look at this when I get in.

timothymarois avatar Nov 11 '18 19:11 timothymarois

Hi @timothymarois,

Im getting an empty array.

My suspicion is that it doesnt properly read the iteration of the nested array. For example, to be able to read the first item I provided above, I should use

accounts[0]['accID'] and will return '123'

But if i use only the query,

accounts.accID is considered as accounts['accID']

Maybe if we can use something like a wild card in between?

Example: ....query->where("accounts.*.accID", "=", "123")->results();

klopez0017 avatar Nov 12 '18 10:11 klopez0017

@klopez0017 I do see what you mean now. Its because it's in an array which doesn't know which to choose from since there is multiple. But still, that is a good point and should be addressed. I do like the functionality of setting accounts.accID = 123 It should intelligently find the correct array.

One thing to note about querying, at least in current form. It was designed to return the entire document as a whole, using queries to find documents instead of partial data. There are Custom Filters which not sure if it is something you could use in this case, or we could modify that if it gets your results.

timothymarois avatar Nov 12 '18 17:11 timothymarois

@timothymarois I will have a look on custom filters thank you. I'll try as well to help fix it and make a pull request to check if the Queried item is multi-nested array inside.

Below is a partially working code for a multi-nested array. It now successfully returns the first arrays.

    /**
    * field
    *
    * Gets property based on a string
    *
    * You can also use string separated by dots for nested arrays
    * key_1.key_2.key_3 etc
    *
    * @param string $field
    * @return string $context property
    */
    public function field($field)
    {
        $parts   = explode('.', $field);
        $context = $this->data;

        if ($field=='data')
        {
            return $context;
        }

        foreach($parts as $part)
        {
            if (trim($part) == '')
            {
                return false;
            }

            if (is_object($context))
            {
                if(!property_exists($context, $part))
                {
                    return false;
                }

                $context = $context->{$part};
            }
            else if (is_array($context))
            {                
                if(!array_key_exists($part, $context))
                {
                    /** A little modification with the code due to its an array inside */
                    if (is_array($context)) {
                        foreach($context as $item){
                            
                            if(!array_key_exists($part, $item))
                            {
                                return false;
                            }
                            return $item[$part];
                        }
                    }
                    return false;
                }
                
                $context = $context[$part];
            }
        }

        return $context;
    }

klopez0017 avatar Nov 13 '18 07:11 klopez0017