Querying a nested array in MongoDB - javascript

This is my posting document in MongoDB:
{
"_id": {
"$oid": "5b4e60ab24210138f5746402"
},
"type": [
"full",
"temp"
],
"applications": [
{
"_id": {
"$oid": "5b52113d1123631744fa9f39"
},
"applicationDate": {
"date": 20,
"day": 5,
"hours": 18,
"minutes": 43,
"month": 6,
"seconds": 41,
"time": 1532105021753,
"timezoneOffset": -120,
"year": 2018
},
"userId": {
"$oid": "5b51fb6f9686430cee31a0d9"
},
"resume": {
"fieldname": "resume",
"originalname": "resume_acc.pdf",
"encoding": "7bit",
"mimetype": "application/pdf",
"destination": "./public/resumes/",
"filename": "765d650b9014cc3ddadb801d10d495a5",
"path": "public/resumes/765d650b9014cc3ddadb801d10d495a5",
"size": 8
},
"coverLetter": {
"fieldname": "docs",
"originalname": "cover letter.pdf",
"encoding": "7bit",
"mimetype": "application/pdf",
"destination": "./public/resumes/",
"filename": "e5892869b24f3fc5e72d3e057b4dd61d",
"path": "public/resumes/e5892869b24f3fc5e72d3e057b4dd61d",
"size": 5
}
}
],
"creatorId": {
"$oid": "5b4b95cc16778c325010a55d"
},
"title": "Developer",
"salary": "50/h",
"timeLine": "One year",
"description": "You'll be building apps",
"duties": "Building apps",
"experience": "2 years",
"province": "ON",
"visible": true,
"__v": 0
}
Postings is an array of posting, which look like the above document. applications is an array which is in every posting. I want to search all postings.applications to see get all postings the user applied to. For now I tried to do it like this:
var Posting = require('../models/posting');
var postings = await Posting
.find({'visible': true});
console.log('posts', postings);
var applications = await Posting
.find({'visible': true})
.where(postings
.map(posting => posting.applications
.map(application => application.userId.equals(req.user._id)))
);
But obviously this failed.
I tried this as well:
var postings = await Posting
.find({'visible': true, 'applications[$].userId': req.user._id});
or
var postings = await Posting
.find({'visible': true, 'applications.$.userId': req.user._id});
But no luck. They both return an empty array.
Posting model:
var mongoose = require('mongoose');
jobPostingSchema = mongoose.Schema({
"creatorId": mongoose.Schema.Types.ObjectId, //ObjectID('aaaa'), // ID of the User or Account
"eventId": {'type': mongoose.Schema.Types.ObjectId, 'default': undefined},
"title": String,
"type": [], //"Full", // What this means? I did not understand.
"salary": String,
"timeLine": String, // What this means? I did not understand.
"description": String,
"duties": String,
"experience": String,
"province": String, // Employer will post job postings based on the province and region
// Applications means, how many people applied for this job post?
"applications": [
// {
// ObjectID: cccc,
// userId: dddd,
// Resume: {},
// coverLetter: String,
// },
],
"visible": Boolean,
});
module.exports = mongoose.model('posting', jobPostingSchema);
So how can I get all applications where userId equals req.user._id?

Maybe this works as a solution ( sourcing from the SO link shared by #DSCH here ):
Posting.find({
'applications': {
$elemMatch: { userId: req.user._id }
},
'visible:': true
});
If you wish to seek clarification on how it works, you may refer to the link here

Posting.find({
'visibile:': true,
'applications': {
$elemMatch: { userId: req.user._id }
}
});
$elemMatch is the mongo operator that you probably need.
Hope that one helps better.

Related

How do I update only certain keys of existing objects in Mongodb?

So this is my case:
In my angular 8 application i create invoices. this is an invoice object:
{
"_id": {
"$oid": "5ea9ad58f65d8d49841362bd"
},
"details": [
{
"_id": "5ea1eff27a1fcb29c4e7d1b6",
"Client": "test",
"km": 88,
"Subject": "test",
"Location": "test",
"StartTime": "2020-04-27T09:00:00.000Z",
"EndTime": "2020-04-27T17:00:00.000Z",
"IsAllDay": false,
"StartTimezone": null,
"EndTimezone": null,
"Description": "oekfokef",
"RecurrenceRule": "FREQ=DAILY;INTERVAL=1;COUNT=5;",
"Id": 2,
"CreatedBy": "bob"
},
{
"_id": "5ea1f36297a9a315bc8ed078",
"Client": "test",
"km": 88,
"Subject": "ewfwefwe",
"Location": "fwefwefwefewfwefwef",
"StartTime": "2020-04-20T09:00:00.000Z",
"EndTime": "2020-04-20T17:00:00.000Z",
"IsAllDay": false,
"StartTimezone": null,
"EndTimezone": null,
"Description": "wefwefewfwef",
"RecurrenceRule": "FREQ=DAILY;INTERVAL=1;COUNT=5;",
"Id": 3,
"CreatedBy": "bob"
},
{
"_id": "5ea1f38d97a9a315bc8ed083",
"Client": "test2",
"km": 38,
"Subject": "test",
"Location": "test",
"StartTime": "2020-05-04T09:00:00.000Z",
"EndTime": "2020-05-04T16:00:00.000Z",
"IsAllDay": false,
"StartTimezone": null,
"EndTimezone": null,
"Description": "test",
"RecurrenceRule": "FREQ=DAILY;INTERVAL=1;COUNT=5;",
"Id": 4,
"CreatedBy": "bob"
}
],
"client": "Robin",
"hoursWorked": 75,
"kmsTravelled": 880,
"invoiceDate": "2020-04-29T16:37:44.948Z",
"paid": "false",
"subTotal": 3917.2,
"travelexpenses": 167.2,
"tax": 879.7,
"hoursCosts": 3750,
"total": 4796.9,
"createdBy": "bob",
"__v": 0
}
But during the use of the application, certain properties change value, like hoursWorked, total, kmTravelled, hourCosts and details. The updated objects get printed to the console. So whenever the user opens the component, i want it to post the whole object, but if an invoice with that Client name alread exists , only update those properties of each invoice per client.
the updated object is this.invoice:
this.invoice = {
client: element.Client,
hourCosts: (element.difference)*this.Client.price,
hoursWorked: (element.difference),
kmsTravelled: element.km,
travelexpenses: this.Client.kmPrice* element.km,
subTotal: (this.Client.kmPrice* element.km) + ((element.difference)*this.Client.price),
total: ((this.Client.kmPrice* element.km) + ((element.difference)*this.Client.price)) + ((this.Client.kmPrice* element.km)+((element.difference)*this.Client.price) * this.tax/100),
createdBy: this.userName,
details: this.details
}
So how do I go about this? Sorry for a quite vague question, but i stuck with this quite a while now. If you need more info please let me know
You could query by 'id' to search for specific values that have changed with something like: db.getCollection('hourCosts').find({_id:'5ea9ad58f65d8d49841362bd'})
Searching in a collection by id with .find() will be efficient. There's a really helpful mongoose doc page here.
Also, just clarifying, you're posting the full customer schema if the name is unique, otherwise updating the relevant invoices by 'client', is that correct? The doc page linked should be useful for most query types and you can create additional mongoose schemas for some added granularity in what content you change.
you can use mongoDB $set in the update command, example:
db.city.update({_id:ObjectId("584a13d5b65761be678d4dd4")}, {$set: {"citiName":"Jakarta Pusat"}})
make sure you are passing the _id as ObjectId
https://www.djamware.com/post/58578ab880aca715e80d3caf/mongodb-simple-update-document-example

Passing a parameter between multiple intents triggering Dialogflow's Fulfillment

I have a Dialogflow agent that I've setup with a web hook that is pulling info from a Firebase database. I am trying to have different intents kick off different queries on the DB. From the Welcome Intent the agent asks for a name that it will matching the DB (e.g. Hi it's nice to meet you? What is the name you looking for?). From there the user is gives a name which is a response that triggers another intent called "name." This intent has a parameter called "agent.parameters.defaultName" which is passed into the fulfillment and used to query the DB. Below is the webhook kicks off the following script:
});
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request,
response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' +
JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
//function to request bio info on the db
function handleData(agent) {
const congressName = agent.parameters.congressName;
return admin.database().ref().once("value").then((snapshot) => {
var nameInfo = snapshot.child('Name/' + congressName + '/profile').val();
agent.add(nameInfo + "\n \n Tell me the first and last name of the next
person you'd like to learn about. Or you can say Twitter to get this
individual's Twitter info.");
});
}
//Function to return the name's tweet info
function handleTweet(agent) {
const congressName = agent.parameters.congressName;
return admin.database().ref().once("value").then((snapshot) => {
var nameTweet = snapshot.child('Name/' + congressName + '/twitter_handle').val();
agent.add(nameTweet);
});
}
// Run the proper function handler based on the matched Dialogflow intent
name
let intentMap = new Map();
intentMap.set('name', handleData);
intentMap.set('name - custom', handleTweet);
agent.handleRequest(intentMap);
});
This returns the bio and prompts the user to say another name or say twitter to pull the twitter info.
If the user says Twitter I'd like for another intent to be triggered. This Intent would also have a fulfillment that would call the DB, but this time it'd pull the Twitter info. Where I'm having an issue is I can't get this intent to trigger the fulfillment. I'm wondering if my parameter is in the right section or if I need to figure out how to pass it to the Twitter intent. I'm not sure where I'm off.
Below are the intents:
//Name intent
{
"id": "0c7bd173-e7fe-4bb4-9b87-7b94624ceb4e",
"name": "name",
"auto": true,
"contexts": [],
"responses": [{
"resetContexts": false,
"action": "congressName",
"affectedContexts": [{
"name": "Name",
"parameters": {},
"lifespan": 5
}],
"parameters": [{
"id": "a79559d6-d3db-4b37-b681-174fce8bc58c",
"required": true,
"dataType": "#sys.any",
"name": "congressName",
"value": "$congressName",
"prompts": [{
"lang": "en",
"value": "What is the proper first and last name of the person you
are looking for info on?"
}],
"isList": false
}],
"messages": [{
"type": 0,
"lang": "en",
"speech": []
}],
"defaultResponsePlatforms": {},
"speech": []
}],
"priority": 500000,
"webhookUsed": true,
"webhookForSlotFilling": false,
"lastUpdate": 1535995990,
"fallbackIntent": false,
"events": []
}
[{
"id": "a14768b0-c64d-4a63-9ccb-d9452b74ed21",
"data": [{
"text": "tammy duckworth",
"alias": "congressName",
"meta": "#sys.any",
"userDefined": false
}],
"isTemplate": false,
"count": 0,
"updated": 1535223341
},
{
"id": "520acfc8-102b-4e14-9342-54678e9f6940",
"data": [{
"text": "tom cotton",
"alias": "congressName",
"meta": "#sys.any",
"userDefined": false
}],
"isTemplate": false,
"count": 0,
"updated": 1535223341
}
]
//Twitter intent
"id": "78330811-d692-4c70-adb2-3130b608d46f",
"name": "twitter",
"auto": true,
"contexts": [],
"responses": [{
"resetContexts": false,
"action": "",
"affectedContexts": [],
"parameters": [{
"id": "7acd4cb2-9cd7-4c2a-b5aa-2981ee25acf4",
"dataType": "#congressName",
"name": "congressName",
"value": "$congressName",
"isList": false
}],
"messages": [{
"type": 0,
"lang": "en",
"speech": []
}],
"defaultResponsePlatforms": {},
"speech": []
}],
"priority": 500000,
"webhookUsed": true,
"webhookForSlotFilling": false,
"lastUpdate": 1535996186,
"fallbackIntent": false,
"events": []
}
[{
"id": "4f099a33-74c6-4832-acd1-815aca6605f2",
"data": [{
"text": "Susan Collins",
"alias": "congressName",
"meta": "#congressName",
"userDefined": false
},
{
"text": " Twitter",
"userDefined": false
}
],
"isTemplate": false,
"count": 0,
"updated": 1535996186
},
{
"id": "f775749a-56fd-410d-a167-174e6eb03ddf",
"data": [{
"text": "twitter ",
"userDefined": false
},
{
"text": "#congress",
"alias": "congressName",
"meta": "#congressName",
"userDefined": true
}
],
"isTemplate": false,
"count": 0,
"updated": 1535238371
}
]

re-map json object for messaging

I'm trying to re-map twitter direct messages data into conversation for mongodb.
"events": [
{
"type": "message_create",
"id": "1023372540847312900",
"created_timestamp": "1532826001737",
"message_create": {
"target": {
"recipient_id": "605675237"
},
"sender_id": "1020464064684806146",
"source_app_id": "268278",
"message_data": {
"text": "all right mate thank you too",
"entities": {
"hashtags": [],
"symbols": [],
"user_mentions": [],
"urls": []
}
}
}
},
{
"type": "message_create",
"id": "1023372444210524164",
"created_timestamp": "1532825978697",
"message_create": {
"target": {
"recipient_id": "1020464064684806146"
},
"sender_id": "605675237",
"message_data": {
"text": "Okay thank you mate, this is distinquish",
"entities": {
"hashtags": [],
"symbols": [],
"user_mentions": [],
"urls": []
}
}
}
},
{
"type": "message_create",
"id": "1023372325150965765",
"created_timestamp": "1532825950311",
"message_create": {
"target": {
"recipient_id": "1020464064684806146"
},
"sender_id": "69565292",
"message_data": {
"text": "Hello strow bree how are you",
"entities": {
"hashtags": [],
"symbols": [],
"user_mentions": [],
"urls": []
}
}
}
},
{
"type": "message_create",
"id": "1023245595790778372",
"created_timestamp": "1532795735677",
"message_create": {
"target": {
"recipient_id": "605675237"
},
"sender_id": "1020464064684806146",
"source_app_id": "268278",
"message_data": {
"text": "Once at a social gathering, Gladstone said to Disraeli",
"entities": {
"hashtags": [],
"symbols": [],
"user_mentions": [],
"urls": []
}
}
}
},
{
"type": "message_create",
"id": "1023245133637140484",
"created_timestamp": "1532795625491",
"message_create": {
"target": {
"recipient_id": "1020464064684806146"
},
"sender_id": "605675237",
"message_data": {
"text": "On Krat's main screen appeared the holo image of a man, and several dolphins. From the man's shape, Krat could tell it was a female, probably their leader. \"...stupid creatures unworthy of the name `sophonts.' Foolish, pre-sentient upspring of errant masters. We slip away from all your armed might, laughing at your clumsiness! We slip away as we always will, you pathetic creatures. And now that we have a real head start",
"entities": {
"hashtags": [],
"symbols": [],
"user_mentions": [],
"urls": []
}
}
}
}
],
"apps": {
"268278": {
"id": "268278",
"name": "Twitter Web Client",
"url": "http://twitter.com"
}
}
}
I'm trying to change this data into this;
[{
members: [ '605675237', '1020464064684806146' ],
messages: [
{ author: '605675237', body: 'On Krats main screen appeared the holo image of a man, and several dolphins. From the mans shape, Krat could tell it was a female, probably their leader ...stupid creatures unworthy of the name sophonts Foolish, pre-sentient upspring of errant masters. We slip away from all your armed might, laughing at your clumsiness! We slip away as we always will, you pathetic creatures. And now that we have a real head start' },
{ author: '1020464064684806146', body: 'Once at a social gathering, Gladstone said to Disraeli' }
{ author: '605675237', body: 'Okay thank you mate, this is distinquish' }
{ author: '1020464064684806146', body: 'all right mate thank you too' },
]
},
{
members: ['69565292', '1020464064684806146'],
messages: [
{ author: '69565292', body: 'Hello strow bree how are you' }
]
}]
user_id1 must be sender_id and user_id2 must be recipient_id but actually, I have to group the twitter DM Objects by sender_id and recipient_id probably.
How can I solve this problem easily any suggestion?
Maybe we can use Lodash or Underscore to solve this remapping easily.
The solution is the group the messages by the user ids, I have created a hashed from the ids to fit it into an object:
const normalized = {};
data.events.forEach(event => {
// Just of easier access
const message = event.message_create;
// Create a temp hash which identify 2 user conversation.
// The hash is just the 2 ids with a `|` separated them
const hashedUsers = [message.sender_id, message.target.recipient_id].sort().join('|');
// The end object you wanted
const normalizedMessage = {
author: message.sender_id,
body: message.message_data.text
};
// Check if we already have this 2 users conversations, create a list of their messages
if (!normalized.hasOwnProperty(hashedUsers)) {
normalized[hashedUsers] = [normalizedMessage];
} else {
normalized[hashedUsers].push(normalizedMessage);
}
});
// Now we have a normalized object, the keys are the hash we created and the values are their messages
// so we can create the object you wanted:
const output = []
Object.entries(normalized).forEach(([key, value]) => {
output.push({
members: key.split('|'),
messages: value
})
})

Unable to get entire information from linkedIn api

I have tried this
Html:
<a id="li_ui_li_gen_1432549871566_0-link" class="" href="javascript:void(0);" onclick="onLinkedInLoad();" style="margin-bottom: 20px;">
JS code:
function onLinkedInLoad(logintype) {
IN.User.authorize(function(){
callback();
});
}
function callback(){
IN.Event.on(IN, "auth", OnLinkedInAuth);
OnLinkedInAuth();
}
function OnLinkedInAuth(){
IN.API.Profile("me")
.fields("firstName", "lastName", "industry", "location:(name)", "picture-url", "headline", "summary", "num-connections", "public-profile-url", "distance", "positions", "email-address", "educations:(id,school-name,field-of-study,start-date,end-date,degree,activities,notes)","languages:(id,language:(name),proficiency:(level,name))","skills:(id,skill:(name))", "date-of-birth")
.result(ShowProfileData)
.error(displayProfilesErrors);
}
function ShowProfileData(profiles) {
console.log(profiles); return false;
//its gives me json responce
/* {
"_total": 1,
"values": [{
"_key": "~",
"distance": 0,
"emailAddress": "xxxxx#gmail.com",
"firstName": "xxxx",
"headline": "xxxxx",
"industry": "Information Technology and Services",
"lastName": "xxx",
"location": {"name": "xxx Area, India"},
"numConnections": 117,
"positions": {
"_total": 1,
"values": [{
"company": {
"id": xxxxx,
"industry": "E-Learning",
"name": "xxxx",
"size": "501-1000 employees",
"type": "Privately Held"
},
"id": 485779823,
"isCurrent": true,
"startDate": {
"month": 2,
"year": 2013
},
"title": "xxxxx"
}]
},
"publicProfileUrl": "https://www.linkedin.com/pub/xxxxx/xx/xx/xx"
}]
} */
}
function displayProfilesErrors(error) {
profilesDiv = document.getElementById("profiles");
profilesDiv.innerHTML = error.message;
console.log(error);
}
It looks to me that some queried fields (e.g. languages, skills, education fields) require that your application have been approved for the Apply with LinkedIn program.
See: Profile field descriptions page which lists fields that require an additional API (i.e. 'Member profile fields available to Apply with LinkedIn developers' title), and see how one can apply for using this API: Request access to this API page.

How do I expand nested relationships in REST API using Sails.js

I am a newbie to NodeJS and Sails.js.
I want create a REST API that allows me to expand a resource based on query parameter. For eg
HTTP GET /snippets
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"url": "http://localhost:8000/snippets/1/",
"highlight": "htep://localhost:8000/snippets/1/highlight/",
"title": "test",
"code": "def test():\r\n pass",
"linenos": false,
"language": "Clipper",
"style": "autumn",
"owner": "http://localhost:8000/users/2/",
"extra": "http://localhost:8000/snippetextras/1/"
}
]}
HTTP GET /snippets?expand=owner
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"url": "http://localhost:8000/snippets/1/",
"highlight": "http://localhost:8000/snippets/1/highlight/",
"title": "test",
"code": "def test():\r\n pass",
"linenos": false,
"language": "Clipper",
"style": "autumn",
"owner": {
"url": "http://localhost:8000/users/2/",
"username": "test",
"email": "test#test.com"
},
"extra": "http://localhost:8000/snippetextras/1/"
}
]}
Wondering how can I do that in Sails.js or NodeJS?
You should use assocations.
Here is how you would create a one-to-many association between your User model and your Snippet model:
// User.js
module.exports = {
// ...
attributes: {
// ...
snippets: {
collection: 'Snippet',
via: 'owner'
}
}
};
// Snippet.js
module.exports = {
// ...
attributes: {
// ...
owner: {
model: 'User'
}
}
};
Then you can hit /snippets if you want a list of snippets, and hit /snippets?populate=[owner] if you need details about the owners of the snippets.

Categories