{
"$and":[ {
"mobile_nos":{
"$regex":{
"regex":"^((?!Nagpur).)*$",
"flags":"i"
}
}
},
{
"full_name":{
"$regex":{
"regex":"^((?!pune).)*$",
"flags":"i"
}
}
}
]
}
Above MongoDB query doesn't yield any result because the mobile_nos field does not exist in the document.
So how can I change the query so that it returns a result if field doesn't exist in document?
You could try the following query which uses the $or operator for the logical condition that use the regex search if the the field exists OR don't use it if the field does not exist (with the $exists operator).
No need to specify the $and operator in the case since MongoDB provides an implicit AND operation when specifying a comma separated list of expressions. Using an explicit AND with the $and operator is necessary when the same field or operator has to be specified in multiple expressions:
{
"$or": [
{
"mobile_nos": {
"$regex": {
"regex": "^((?!Nagpur).)*$",
"flags": "i"
}
}
},
{ "mobile_nos": { "$exists": false } }
],
"full_name": {
"$regex": {
"regex": "^((?!pune).)*$",
"flags": "i"
}
}
}
Try using $or with $exists:
{
"$and":[ {
$or:[
{
"mobile_nos":{
"$regex":{
"regex":"^((?!Nagpur).)*$",
"flags":"i"
}
},
{
"mobile_nos":{
$exists: false
}
}
]
}
},
{
"full_name":{
"$regex":{
"regex":"^((?!pune).)*$",
"flags":"i"
}
}
}
]
}
Related
I'm having trouble understanding how #scope directive works. When I add the directive to query definition and give the IsOwner: true Lighthouse adds it to the scope but the problem starts when I change it to IsOwner:false. Lighthouse still applies the scope into the query. Only time Lighthouse doesn't apply the scope when I remove IsOwner parameter from the query.
My query definition is like following;
listings(IsOwner: Boolean #scope(name:"IsOwner"), where: _ #whereConditions(columnsEnum: "ListingColumn"), orderBy: _ #orderBy(columnsEnum: "ListingColumn")) : [Listing!]! #paginate(maxCount: 50 defaultCount: 10)
And actual query is like below;
query ($min_lng:Float!, $min_lat:Float!, $max_lng:Float!, $max_lat:Float!, $first:Int, $page:Int, $withPaginatorInfo:Boolean!, $withListingImages:Boolean!, $withListingMeta:Boolean!, $withListingViews:Boolean!, $withListingActions:Boolean!, $withListingNotes:Boolean!, $withListingReminders:Boolean!, $withListingViewUser:Boolean = false, $conditions: ListingsWhereWhereConditions, $orderBy: [ListingsOrderByOrderByClause!]) {
listings(
bbox: {
min_lng: $min_lng
min_lat: $min_lat
max_lng: $max_lng
max_lat: $max_lat
}
IsOwner: false
where: $conditions
orderBy: $orderBy
first: $first
page: $page
) {
data {
...listingFields
}
paginatorInfo #include(if: $withPaginatorInfo) {
currentPage
lastPage
}
}
}
Model scope it like following;
public function scopeIsOwner($query)
{
return $query->join('listing_user', 'listing_user.listing_id', '=', 'listings.id')->where('listing_user.user_id', Auth::user()->id);
}
*** UPDATE ***
I figured it out after the comments, I changed the model scope to the following
public function scopeIsOwner($query, $isEnabled)
{
if ($isEnabled) {
return $query->join('listing_user', 'listing_user.listing_id', '=', 'listings.id')->where('listing_user.user_id', Auth::user()->id);
}
return $query;
}
I made minor changes on the schema like below,
listings(scopeIsOwner: Boolean #scope(name:"IsOwner"), bbox: BoundingBoxInput! #builder(method: "App\\GraphQL\\Builders\\BoundingBoxSearch#bbSearch"), where: _ #whereConditions(columnsEnum: "ListingColumn"), orderBy: _ #orderBy(columnsEnum: "ListingColumn")) : [Listing!]! #guard(with: ["api"]) #paginate(maxCount: 50 defaultCount: 10)
My final query and it's variable is like the following,
query ($min_lng:Float!, $min_lat:Float!, $max_lng:Float!, $max_lat:Float!, $first:Int, $page:Int, $withPaginatorInfo:Boolean!, $withListingImages:Boolean!, $withListingMeta:Boolean!, $withListingViews:Boolean!, $withListingActions:Boolean!, $withListingNotes:Boolean!, $withListingReminders:Boolean!, $withListingViewUser:Boolean = false, $scopeIsOwner:Boolean = false $conditions: ListingsWhereWhereConditions, $orderBy: [ListingsOrderByOrderByClause!]) {
listings(
bbox: {
min_lng: $min_lng
min_lat: $min_lat
max_lng: $max_lng
max_lat: $max_lat
}
scopeIsOwner: $scopeIsOwner
where: $conditions
orderBy: $orderBy
first: $first
page: $page
) {
data {
...listingFields
}
paginatorInfo #include(if: $withPaginatorInfo) {
currentPage
lastPage
}
}
}
Variables;
{
"min_lng": 29.0401317,
"min_lat": 41.0028473,
"max_lng": 29.0308512,
"max_lat": 40.9916271,
"withPaginatorInfo" : true,
"first": 10,
"page": 1,
"withListingImages": false,
"withListingMeta": false,
"withListingViews": false,
"withListingActions": false,
"withListingNotes": false,
"withListingReminders": false,
"withListingViewUser": false,
"conditions": {"AND": [{"column": "PRICE", "operator": "LTE","value": "190"}]},
"orderBy": [{ "column": "TENURE_ID", "order": "DESC" }],
"scopeIsOwner": false
}
As you can understand when I give true to scopeIsOwner variable endpoint enables the scope and manipulate the query accordingliy.
You are misunderstanding. See https://lighthouse-php.com/master/api-reference/directives.html#scope
The scope method will receive the client-given value of the argument as the second parameter.
Your scope should react to the argument the client passes.
There is a bug in Lighthouse library. Scope is added when parameter exist without checking value. ScopeDirective class and handleBuilder method are quite simple
public function handleBuilder($builder, $value)
{
$scope = $this->directiveArgValue('name');
try {
return $builder->{$scope}($value);
} catch (BadMethodCallException $exception) {
throw new DefinitionException(
$exception->getMessage()." in {$this->name()} directive on {$this->nodeName()} argument.",
$exception->getCode(),
$exception->getPrevious()
);
}
}
I think $value contains true or false and this variable should not be injected to scope here:
$builder->{$scope}($value);
Instead, should be something like:
if ($value == true) {
$builder->{$scope}();
}
I have this problem where an API responds to me with DEPARTURESEGMENT sometimes containing only one object, and sometimes containing an array of objects. Depending on which case it is, I seem to need different logics in my foreach-loop.
Response A:
{
"getdeparturesresult":{
"departuresegment":[{
"departure":{
"location":{
"#id":"7461018",
"#x":"12.523958",
"#y":"57.938402",
"name":"Noltorps centrum"
},
"datetime":"2014-12-04 23:05"
},
"direction":"Alingsås station",
"segmentid":{
"mot":{
"#displaytype":"B",
"#type":"BLT",
"#text":"Buss"
},
"carrier":{
"name":"Västtrafik",
"url":"http://www.vasttrafik.se/",
"id":"279",
"number":"1"
}
}
},
{
"departure":{
"location":{
"#id":"7461018",
"#x":"12.523958",
"#y":"57.938402",
"name":"Noltorps centrum"
},
"datetime":"2014-12-04 23:05"
},
"direction":"Alingsås station",
"segmentid":{
"mot":{
"#displaytype":"B",
"#type":"BLT",
"#text":"Buss"
},
"carrier":{
"name":"Västtrafik",
"url":"http://www.vasttrafik.se/",
"id":"279",
"number":"1"
}
}
}
]
}
}
Works with this loop:
foreach ($apiData->getdeparturesresult->departuresegment as $m) {
While this response B:
{
"getdeparturesresult":{
"departuresegment":{
"departure":{
"location":{
"#id":"7461018",
"#x":"12.523958",
"#y":"57.938402",
"name":"Noltorps centrum"
},
"datetime":"2014-12-04 23:05"
},
"direction":"Alingsås station",
"segmentid":{
"mot":{
"#displaytype":"B",
"#type":"BLT",
"#text":"Buss"
},
"carrier":{
"name":"Västtrafik",
"url":"http://www.vasttrafik.se/",
"id":"279",
"number":"1"
}
}
}
}
}
needs a loop like this (otherwise it throws an error):
foreach ($apiData->getdeparturesresult as $m) {
Is there a way to write the loop failsafe for whether DEPARTURESEGMENT is an array of objects or just one object (the brackets [] is the only difference to the structure of the json right?) or do I have to somehow test and see first whether DEPARTURESEGMENT is an array or not, and dispatch to two different loops depending on the outcome?
You have a few methods that can help you:
is_array
is_object
instanceof // if you receive specific object
gettype
json_decode second parameter, which if is set to true, tries to decode the json as an array
In you situation, you would probably be fine by doing the following:
if (is_object($entry)) {
handleObject($entry);
} elseif (is_array($entry) && count($entry)) {
foreach ($entry as $e) {
handleObject($e);
}
}
I have this little useful function in my standard repertoire:
function iter($x) {
if(is_array($x))
return $x;
if(is_object($x)) {
if($x instanceof \Iterator)
return $x;
if(method_exists($x, 'getIterator'))
return $x->getIterator();
return get_object_vars($x);
}
return array($x);
}
This way you can use any variable with foreach without having to check it beforehand:
foreach(iter($whatever) as $item)
...
How about checking whether it's an array or not with is_array?
I made a simple example of it's usage here - http://codepad.org/WNjbIPZF
I am writing a function which checks nested keys if it exists in JSON, but i hav stuck at place when if code is correct then it must return true or false but it is not. it returns null value
php function is
function checkNestedKeysExists($JSONRequest,$keyCheckArray){
$currentKey = current($keyCheckArray);
$JSONRequest = array_change_key_case($JSONRequest, CASE_LOWER);
if(array_key_exists($currentKey,$JSONRequest)){
if($currentKey==end($keyCheckArray)){
return true;
}
else {
array_shift($keyCheckArray);
$this->checkNestedKeysExists($JSONRequest[$currentKey],$keyCheckArray);
//echo "F";
}
}
else{
return false;
}
}
given array is
$keyCheckArray = array('data','device_info','deviceid');
and $JSONRequest is
{
"timestamp": "2014-01-01 11:11:11",
"data": {
"requestid": "bcpcvssi1",
"device_info": {
"os": "Android",
"deviceId": "123123",
"userProfile": {
"email": [
"abc#gmail.com"
],
"gender": "Male",
"age": "19",
"interest": [
"Apple",
"Banana"
]
}
}
}
}
Modify the line of your code where you make recursive call like following
return $this->checkNestedKeysExists($JSONRequest[$currentKey],$keyCheckArray);
So it will return the result of the call
pass $JSONRequest in
json_decode($JSONRequest, true);
EDIT: Sorry I got it wrong in first time.
Use array[0] instead of current() if you are shifting elements, maybe it is making a problem. And of course, do the var_dump() to check values.
$currentkey = 'data' and end($keyCheckArray) = 'deviceid'. That will never return true, hence you have no return values specified and it will return null.
two advices:
give the function with every possible way to end the function a valid return value.
create a variable for every fixed outcome like end($keyCheckArray).
If have tested your function (and edited it for testing purposes):
function checkNestedKeysExists($JSONRequest,$keyCheckArray){
$currentKey = current($keyCheckArray);
$JSONRequest = array_change_key_case($JSONRequest, CASE_LOWER);
$endValue = end($keyCheckArray);
if(array_key_exists($currentKey,$JSONRequest)){
print 'currentKey = '.$currentKey.", end = ".$endValue."<br>\n";
if($currentKey== $endValue){
return 'correct';
}else {
array_shift($keyCheckArray);
$p = checkNestedKeysExists($JSONRequest[$currentKey],$keyCheckArray);
print "p = ".$p."<br>\n";
//echo "F";
return $currentKey;
}
}
else{
return false;
}
}
The output is like this:
correct
device_info
data
I suggest you change your function into a while loop. Once you have found the requested result, return true.
Essentially is it possible to find documents based on there sub document using $in. For example say I had:
array(
'item.1',
'item.2',
'item.3
)
would return document that have:
{
item {
1: {
}
}
}
{
item {
2: {
}
}
}
{
item {
3: {
}
}
}
I know if I had one I could use db.inventory.find( { qty: { $exists: true, $nin: [ 5, 15 ] } } ) but how would I do that with a $in?
You can use a query of this form:
db.collection.find ( { $or : [
{"item.1":{$exists:true}},
{"item.2":{$exists:true}},
{"item.3":{$exists:true}}
] } );
This will return any document which has one or more of "item.X" in this case 1, 2 or 3 set.
I have the following json:
{
"Companies":[
{
"CompanyPersonTask":{
"company_id":"502d1844-3638-44dc-824c-14f02e0cc009",
"person_id":"2",
"task_id":"1"
},
"Company":{
"id":"502d1844-3638-44dc-824c-14f02e0cc009",
"name":"mostro",
"Office":[
{
"id":"502d1844-b90c-44f5-84c5-14f02e0cc009",
"company_id":"502d1844-3638-44dc-824c-14f02e0cc009",
"region":"Emilia-Romagna",
"city":"Rozzemilia",
"address":"-",
"phone":"-",
"legal_office":true
}
],
"CompanyPersonTask":[
{
"company_id":"502d1844-3638-44dc-824c-14f02e0cc009",
"person_id":"2",
"task_id":"1"
}
]
},
"Person":{
"id":"2",
"first_name":"Carlo",
"last_name":"Giusti",
"home_address":"Russi",
"job_address":null,
"phone":null,
"fax":null,
"mail":null,
"full_name":"Giusti Carlo",
"OfficePersonTask":[
],
"CompanyPersonTask":[
{
"company_id":"502d1844-3638-44dc-824c-14f02e0cc009",
"person_id":"2",
"task_id":"1"
}
]
},
"Task":{
"id":"1",
"short_name":"Proprietario",
"full_name":null,
"info":null,
"OfficePersonTask":[
],
"CompanyPersonTask":[
{
"company_id":"502d1844-3638-44dc-824c-14f02e0cc009",
"person_id":"2",
"task_id":"1"
}
]
}
}
]
}
That is created by this method, inside CompanyPersonTask model:
public function getCompaniesByRegion($region){
$this->recursive = 2;
return $this->find('all');
}
but I want my json to be formatted like this:
{
"Companies":[
{
"Company":{
"id":"502d1844-3638-44dc-824c-14f02e0cc009",
"name":"mostro",
"Office":[
{
"id":"502d1844-b90c-44f5-84c5-14f02e0cc009",
"company_id":"502d1844-3638-44dc-824c-14f02e0cc009",
"region":"Emilia-Romagna",
"city":"Rozzemilia",
"address":"-",
"phone":"-",
"legal_office":true
}
]
},
"Person":{
"id":"2",
"first_name":"Carlo",
"last_name":"Giusti",
"home_address":"Russi",
"job_address":null,
"phone":null,
"fax":null,
"mail":null,
"full_name":"Giusti Carlo"
}
}
]
}
How can I modify my method?
Use Containable behavior to filter result data.
For more explanation refer this link.
You can check unbindModel in cake php to remove the relation on the fly. This will prevent the data from the unwanted table. Check this.
<?php
$this->Model->unbindModel(
array('associationType' => array('associatedModelClassName'))
);