SequelizeJS primaryKey related include - node.js

I am currently working on a REST API, working with SequelizeJS and Express.
I'm used to Django Rest Framework and I'm trying to find a similar function :
I have a table User and a table PhoneNumber.
I want to be able to return a user in JSON, including the list of the primarykeys of its phone numbers like this :
{
"firstName": "John",
"lastName": "Doe",
"phoneNumbers": [23, 34, 54],
}
Is there a way to do this simply and efficiently in sequelize or do I have to write functions that transform the fields like :
"phoneNumbers": [
{ "id": 23, "number": "XXXXXXXXXX" },
{ "id": 34, "number": "XXXXXXXXXX" },
{ "id": 54, "number": "XXXXXXXXXX" }
]
into what I have above ?
Thank you,
Giltho

Sequelize finder-methods accept and option attribute that lets you define which properties of a model it should query for. See http://docs.sequelizejs.com/manual/tutorial/querying.html#attributes
That works for joins too:
User.all({
include: [
{ model: Phonenumber, attributes: ['id']}
]
})
.then(function(users) {
})
will execute
SELECT user.*, phonenumber.id FROM user INNER JOIN phonenumber ON ...
But to turn the phonenumbers into an array of integers [1,2,...] in your api response, you'd still have to map the ids manually into an array, otherwise you get an array of [{"id": 1}, {"id": 2},...].
But actually i recommend not to do that. An array of objects is the more future-proof option than an array of integers. Because your api-client don't need to change anything if you decide some day to expand the phonenumber object with additional attributes.

Related

How to make the mongoose data after populating

for example i have done the populate the data and i don't want the entity at which it's populated for example:
{
"gstin": "27AAATW4187E2UW",
"company_name": "TATA_AUTOCOMP ",
"status": "Hold",
"createdBy": {
"name": "xyz123",
"email": "xyz#yahoo.com",
"mobile_number": 7972512892
}
}
]
right now my data looks like above but i don't want the populated information i want my data just like that anyone help me .
{
"gstin": "27AAATW4187E2UW",
"company_name": "TATA_AUTOCOMP ",
"status": "Hold",
"name": "abcd",
"email": "xyz#gmail.com",
"mobile_number": 1234567890
}
]
in your query when use .populate you can use select and when application run your query just return selected parameters like this :
Model
.findOne({ _id: 'bogus' })
.populate('friendsRequestList', 'name email')
and if you want all result in one level in json you must edit your result with .map .forEach and ....

i can't query over populated children attributes

I am trying to query over populated children attributes using mongoose but it straight up doesn't work and will return empty arrays all the time.
even hardcoding right and existing information as values for the query would return empty arrays.
my schema is a business schema with a 1 to 1 relationship with user schema via the attribute createdBy. the user schema has an attribute name which I am trying to query on.
so if I make a query like this :
business.find({'createdBy.name': {$regex:"steve"}}).populate('createdBy')
the above will never return any documents. although, without the find condition, everything works fine.
Can I search by the name inside a populated child or not? all tutorials say this should work fine but it just doesn't.
EDIT : an example of what the record looks like :
{
"_id": "5fddedd00e8a7e069085964f",
"status": 6,
"addInfo": "",
"descProduit": "",
"createdBy": {
"_id": "5f99b1bea9ba194dec3bd6aa",
"status": 1,
"fcmtokens": [
],
"emailVerified": 1,
"phoneVerified": 0,
"userType": "User",
"name": "steve buschemi",
"firstName": "steve",
"lastName": "buschemi",
"tel": "",
"email": "steve#buschemi.com",
"register_token": "747f1e1e8fa1ecd2f1797bb402563198",
"createdAt": "2020-10-28T18:00:30.814Z",
"updatedAt": "2020-12-18T13:52:07.430Z",
"__v": 19,
"business": "5f99b1e101bfff39a8259457",
"credit": 635,
},
"createdAt": "2020-12-19T12:10:57.703Z",
"updatedAt": "2020-12-19T12:11:16.538Z",
"__v": 0,
"nid": "187"
}
It seems there is no way to filter parent documents by conditions on child documents:
From the official documentation:
In general, there is no way to make populate() filter stories based on properties of the story's author. For example, the below query won't return any results, even though author is populated.
const story = await Story.
findOne({ 'author.name': 'Ian Fleming' }).
populate('author').
exec();
story; // null
If you want to filter stories by their author's name, you should use denormalization.

How to do field mapping in azure search for complex json objects for example nested array

I have following problem
I have a field mapping update to an index .Payload is complex where
I have:
{
"type": "abc",
"Party": [{
"Type": "abc",
"Id": "123",
"Name": "manasa",
"Phone": [{
"Type": "Office",
"Number": "12345"
}]
}]
}
And now I want to create a field for an index. The field name is phonenumber of type Collection(Edm.String)
where mapping is
{
"sourceFieldName" : "/Party/Phone/Number",
"targetFieldName" : "phonenumber",
"mappingFunction" : { "name" : "jsonArrayToStringCollection" }
}
In http post body
But still after indexing i get phone number result as null.That means the mapping went wrong.If you see the phone number in source json, it is inside a json array and it itself is an array and result needs to get stored inside a collection of a string.Is it possible how can I achieve this?
If this is not possible I atleast want field mapping till phone array ie., /Party/Phone/
If i index complete party array as a text, I get an error while running the index saying:
"Field 'partydetails' contains a term that is too large to process. The max length for UTF-8 encoded terms is 32766 bytes. The most likely cause of this error is that filtering, sorting, and/or faceting are enabled on this field, which causes the entire field value to be indexed as a single term. Please avoid the use of these options for large fields."
Can someone please help!
If party would have been a Json object than an array and phone would have been only a string array for example
{
"type": "abc",
"Party": {
"Type": "abc",
"Id": "123",
"Name": "manasa",
"Phone": [{
"12345",
"23463"
}]
}
}
Then I could have mapped
{
"sourceFieldName" : "Party/Phonenumber",
"targetFieldName" : "phonenumbers",
"mappingFunction" : { "name" : "jsonArrayToStringCollection" }
}
It map as collection of type odata EDM.string.
So to put this in better and straight forward way,
Either transform your json to something flatter (the example that I
gave above) or
Use the proper index incase if you know before inhand as
#Luis Cabrera said,
“sourceFieldName”: “/Party/0/Phone/0/Type
It is a limitation from azure search side.
Note that Party and Phone are arrays, so the field mapping you mention won't work.
You will need to index into the specific element. For example:
{
"sourceFieldName": "/Party/0/Phone/0/Type",
"targetFieldName": "firstPhoneNumberTypeOfFirstParty"
}
You may want to give that a shot.
Thanks!
Luis Cabrera | Program Manager | Azure Search

Searching parent id in cloudant

I have a Cloudant DB with the following structure:
{id: 1, resource:”john doe”, manager: “john smith”, amount: 13}
{id: 2, resource:”mary doe”, manager: “john smith”, amount: 3}
{id: 3, resource:”john smith”, manager: “peter doe”, amount: 10}
I needed a query to return the sum of amount, so I've built a query with emit(doc.manager, doc.amount) which returns
{"rows":[
{"key":"john smith","value":16},
{"key":"peter doe","value":10}]}
It is working like a charm. However I need the manager ID along with Manager name. The result I am looking for is:
{"rows":[
{"key":{"john smith",3},"value":16},
{"key":{"peter doe",null},"value":10}]}
How should I build a map view to search the parent ID?
Thanks,
Erik
Unfortunately I don't think there's a way to do exactly what you want in one query. Assuming you have the following three documents in your database:
{
"_id": "1",
"resource": "john doe",
"manager": "john smith",
"amount": 13
}
--
{
"_id": "2",
"resource": "mary doe",
"manager": "john smith",
"amount": 3
}
--
{
"_id": "3",
"resource": "john smith",
"manager": "peter doe",
"amount": 10
}
The closest thing to what you want would be the following map function (which uses a compound key) and a _sum reduce:
function(doc) {
emit([doc.manager, doc._id], doc.amount);
}
This would give you the following results with reduce=false:
{"total_rows":3,"offset":0,"rows":[
{"id":"1","key":["john smith","1"],"value":13},
{"id":"2","key":["john smith","2"],"value":3},
{"id":"3","key":["peter doe","3"],"value":10}
]}
With reduce=true and group_level=1, you essentially get the same results as what you already have:
{"rows":[
{"key":["john smith"],"value":16},
{"key":["peter doe"],"value":10}
]}
If you instead do reduce=true and group=true (exact grouping) then you get the following results:
{"rows":[
{"key":["john smith","1"],"value":13},
{"key":["john smith","2"],"value":3},
{"key":["peter doe","3"],"value":10}
]}
Each unique combination of the manager and _id field is summed, which unfortunately doesn't give you what you want. To accomplish what you want to accomplish, I think your best but would be to sum up the values after querying the database.

Mongoose : how to set a field of a model with result from an agregation

Here is my sample :
Two simple Mongoose models:
a Note model, with among other fields an id field that is a ref for the Notebook model.
a Notebook model, with the id I mentioned above.
My goal is to output something like that:
[
{
"notes_count": 7,
"title": "first notebook",
"id": "5585a9ffc9506e64192858c1"
},
{
"notes_count": 3,
"title": "second notebook",
"id": "558ab637cab9a2b01dae9a97"
}
]
Using aggregation and population on the Note model like this :
Note.aggregate(
[{
"$group": {
"_id": "$notebook",
"notes_count": {
"$sum": 1
}
}
}, {
"$project": {
"notebook": "$_id",
"notes_count": "$notes_count",
}
}]
gives me this kind of result :
{
"_id": "5585a9ffc9506e64192858c1",
"notes_count": 7,
"notebook": {
"_id": "5585a9ffc9506e64192858c1",
"title": "un carnet court",
"__v": 0
}
}
Forget about __v and _id fields, would be easy to handle with a modified toJSON function.
But in this function neither doc nor ret params gives me access to the computed notes_count value.
Obviously, I could manage this in the route handler (parse result and recreate the datas that will be returned) but, is there a proper way to do that with mongoose ?
You can't use the aggregate method to update. As you have noted, you'll need to use output from the aggregate constructor to update the relevant documents.
As the Mongoose aggregate method will return a collection of plain objects, you can iterate through this and utilise the _id field (or similar) to update the documents.

Resources