Am I misunderstanding how nested relationships are...
# box-products
r
Am I misunderstanding how nested relationships are supposed to work with the Mementifier module?
The docs say, "...if a
User
has a
Role
relationship and you want to include only the
roleName
property, you can do
role.roleName
". I have two objects, an
Incident
and a
Shop
with the Quick relationship defined in
Incident
as...
Copy code
function shop() {
	return belongsTo( 'Shop@v1' );
}
...and the following
Incident
memento as...
Copy code
this.memento = {
	defaultIncludes: [
		'id'
		,'name'
		,'status'
		,'shop.postcode:postcode'
	]
}
... and of course I was expecting a
postcode
key in the returned structure but instead I got the whole
Shop
memento contained in a
shop
key in my structure. I've tried to read the code but it's beyond my pay grade. What configuration am I missing or not understanding?
s
You can't skip an intermediary object. when relying on the convention. If you want
a.b.c
then it will call
a.getShop()
and that's
b
and then
b.getPostcode()
- I don't think you need
:postcode
in there. As an alternative, you could add a subselect on
a
so postcode becomes a property on a and you don't need the intermediary object, which is expensive anyway. Or you could make a mapper that just pulls in that one field, but then you're still paying for the intermediary object instantiation
r
You can't skip an intermediary object
Ah, okay, so are the docs wrong? I got the impression that was the use case it was describing?
I don't think you need
:postcode
in there
Yes, typo in my example, it should have been
:post_code
you could add a subselect on
a
Okay, I need to look into that.
Or you could make a mapper
Yes, I find that later and produced this which seems to work for me
Copy code
,mappers: {
	'post_code': function( item, memento ) { return item.postcode }
}
s
A subselect is likely better here. With that mapper you're still pulling in all of B even though you only need b.c.thing
The docs are correct. You're not skipping the intermediary item with a mapper. You're just not using it in your output
With a subselect you are skipping it, or at lest delegating the work to the DB
r
Thanks for the insight, I'll go away and take another look at subselects 👍
e
You might need to
ignoreDefaults
or something like that to avoid getting the entire Shop object in the output. The default for Quick entities is to include the defined attributes.
r
Yep @sknowlton, a scoped subselect worked a treat, once I figured out how to wire it up.
Copy code
function scopeAddPostCode( qb ) {
	qb.addSubSelect( 'post_code', 'shop.postCode' );
}
Copy code
this.memento = {
	defaultIncludes: [
		'id'
		,'name'
		,'status'
		,'post_code'
	]
}
@elpete I didn't seem to need that
ignoreDefaults
, unless I'm missing something? My next challenge is to get a value I'm calling
shopName
which will be a concatenation of the
city
and
postCode
fields with a
,
between from the related
shops
table. I tried...
Copy code
function scopeAddShopName( qb ) {
	qb.addSubSelect( 'shopName', "concat(shop.city, ', ', shop.postcode) AS shopName" );
}
...but no joy - "_Quick couldn't figure out what to do with [concat(shop]._" I then tried...
Copy code
function scopeAddShopName( qb ) {
	qb.addSubSelect( 'shopName', function( q ) {
		q.selectRaw( "concat(shop.city, ', ', shop.postcode) AS shopName" )
			.from( "shops" )
			.whereColumn( "incidents.shopPK", "<http://shops.pk|shops.pk>" );
	} ).from( "incidents" );
}
...but then got "_variable [SUBSELECTQUERY] doesn't exist_". Not sure what to try next?
e
That last
from( "incidents" )
looks like it might be in the wrong place.
My bit about
ignoreDefaults
was how to get the entire Shop object but only use certain fields from it.
The biggest thing to look out for here is performance. One subselect, probably fine. But the more you get the more work it is for the server. Each subselect is basically it’s own mini join to find the data.
Finally, if you are already bringing back
post_code
and
shopCity
you could use mementifier to add a mapper to create
shopName
yourself.
r
That last
from( "incidents" )
looks like it might be in the wrong place.
That was an amalgam from Quick docs and the QB docs thinking a SelectRaw might help. I'll looks a mapper, thanks.