Create MongoDB field with a values from populated document - javascript

I have a users collection and Companies collection. Right now the output looks like this:
"_id":"5ce543a5390d87567f523153",
"updatedAt":"2019-10-18T15:01:53.812Z",
"createdAt":"2019-05-22T12:42:13.046Z",
"associatedCompany":{
"_id":"5ce543a4390d87567f523148",
"companyName":"Company Two"},
"accountStatus":1,
"roleInfo":{"roleType":1},
"role":2,
"personalInfo":{
"fullName":"SomeName",
"firstName":"Name",
"lastName":"Last",
"email":"email#email.com",
"phone":{"countryCode":"SE","number":"9876543210"}}}
Where company field is populated from Company collection.
Is there a way to display just a company name right away with firstName and lastName field without "personalInfo" field so the output will look like:
{"data":[{
"_id":"5ce543a5390d87567f523153",
"updatedAt":"2019-10-18T15:01:53.812Z",
"createdAt":"2019-05-22T12:42:13.046Z",
"companyName":"Company Two",
"accountStatus":1,
"roleInfo":{"roleType":1},
"role":2,
"firstName":"Name",
"lastName":"Last",
"email":"email#email.com"
Query I am using
const listUsers = (skip, limit = 10) => {
let config = {
populate: {
'path': 'associatedCompany',
'select': 'companyName'
},
limit: Number(limit),
skip: Number(skip),
};
I have tried to do it with aggregation and lookup but without success.
Thanks is advance.

Use projection to filter the fields that you want to be displayed in your output.
Refer:
mongoDB projection

Related

Trying to generate an array of hashes in Node from model object

In order to send an email to multiple recipients via SendGrid API v3 using a dynamic template, I need to pass an email parameter like:
"to":[
{
"email":"example1#example.com"
},
{ "email": "example2#example.com"
}
],
Obviously I am not wanting to hard code these email addresses s.t. they are dynamic.
I currently generate a list of emails with this code:
// loop through users
var users = group.user;
var emails = users.map(function (obj) {
return obj.email;
});
Which returns eg:
[ 'example1#example.com',
'example2#example.com' ]
How do I return instead the array of hashes:
[
{
"email":"example1#example.com"
},
{ "email": "example2#example.com"
}
]
Maybe what you are trying to say is hashmap, not hashes, if not, I don't understand the question.
To achieve the lists of maps that you mention, your code should be something like:
// loop through users
var users = group.user;
var emails = users.map(function (obj) {
return {email: obj.email};
});
Every item of the list would have email as key, and the email as value.
What is a hash: https://en.wikipedia.org/wiki/Hash_function
What is a hash table: https://en.wikipedia.org/wiki/Hash_table
What is a js object: https://www.w3schools.com/js/js_objects.asp

How to correctly find objects by proximity using sequelize.js and PostGIS?

I'm trying to perform a simple ST_Dwithin search using sequelize.js and PostGIS.
In my database I have 3 tables of interest: Users, Neighborhoods and Addresses. All geo data is stored inside addresses table, which has references to users and neighborhoods.
return Neighborhood.findById(id).then(neighborhood => {
return neighborhood.getAddress().then(address => {
return Address.findAll({
where: sequelize.where(
sequelize.fn(
'ST_DWithin',
sequelize.fn(
'ST_Transform',
address.position,
26986),
sequelize.fn('ST_Transform',
sequelize.col('position'),
26986),
distance),
true
)
})
})
}).catch(err => new Error(err));
First I get the address of a neighborhood and then use sequelize.fn to query with PostGIS ST_DWithin function. However this throws an error TypeError: val.replace is not a function. I believe it is something with line address.position. The column position in the table Addresses stores geometry points with type GEOMETRY and srid 4326.
The function works correctly if instead of address.position I hard code something like sequelize.fn('ST_GeomFromText', 'POINT(39.807222 -76.984722)', 4326)
In my case, the geometry(point) attribute is in the User entity. This is what I got working:
var lat = parseFloat(json.lat);
var lng = parseFloat(json.lng);
var attributes = Object.keys(User.attributes);
var distanceAttribute =
sequelize.fn('ST_Distance_Sphere',
sequelize.literal('geolocation'),
sequelize.literal('ST_MakePoint('+lat+','+lng+')'));
var distanceAlias = [distanceAttribute, 'distance'];
attributes.push(distanceAlias);
var query = {
attributes: attributes,
where: sequelize.where(distanceAttribute, {$lte: 100000}),
logging: console.log
}
User.findAll(query)
.then(function(instance){
console.log(instance);
});
Which produces a SQL like this:
SELECT "user_id", "user_name" ... ST_Distance_Sphere(geolocation,
ST_MakePoint(-22.4149023,-47.56513940000002)) AS "distance"
FROM "user" AS "User"
WHERE ST_Distance_Sphere(geolocation,
ST_MakePoint(-22.4149023,-47.56513940000002)) <= 100000;
I think this should work for you too by changing User to Address

Javascript Query Builder with MongoDB "$in" operator

So I have set up a query builder that builds a query based on the users interaction with the data filtration area on the front end which contains a lot of radio buttons and dropdown boxes etc. Similar to what eBays data filtration function provided on their website.
My Query Builder so far:
app.post('/user/test',function(req, res) {
var query = {};
if (req.body.region){
query.region = req.body.region
console.log(query.region)
}
if(req.body.sector){
query.sector = req.body.sector
console.log(query.sector)
}
if(req.body.client){
query.client = req.body.client
console.log(query.client)
}
Project.find(query, function(err, project){
if (err){
res.send(err);
}
console.log(project);
res.json(project);
});
});
Now the above works very well. I can send filtration options in any scenario and it will bring back the required result. For example I can only send the region name and it will give me all the data that belongs to that region or I can send region name, sector name and it will further filter down the data that matches region and sector name sent and so on.
The Issue:
Now my database contains an array of data like:
words: ["book", "table", "pen"]
Each object in the database will have this array. So if there are 100 objects in the database each has one of these will have the "words" array with different or similar values.
I want to be able to send multiple options like "table" , "pen" to my database and get all the objects that contains the those two options within the data array.
To achieve that I did the following:
if (req.body.sol){
var arr = [];
arr.push(req.body.sol)
query.words = {words: {$in: arr}}
}
The above Did not work.
But if I make the following changes to this line:
From
query.words = {words: {$in: arr}}
to
query = {words: {$in: arr}}
Making the above change does work but then it does not build the remaining queries. It only builds the "$in" query.
Any idea how I can fix this?
you can simply write the query like
query.words = {$in: arr}
This way you would be able to build rest of the query.
the reason why query.words = {words: {$in: arr}} fails is that the query becomes{words:{words: {$in: arr}}}, which is not what you want, since its trying to find words inside words.
instead using query.words = {$in: arr} will make your query {words: {$in: arr}
You can use the bracket notation to add the $in operator in your query properties:
if (req.body.sol){
var arr = [],
obj = {};
arr.push(req.body.sol);
obj["$in"] = arr;
query.words = obj;
}

How can I make Parse.Query.AND?

I need to connect 2 queries in Parse.com with an and, my code is:
var queryDeseo1 = new Parse.Query(DeseosModel);
queryDeseo1.equalTo("User", Parse.User.current());
queryDeseo1.equalTo("Deseo", artist);
queryDeseo1.find({...
The result of the .find is all the objects with User = Parse.User.current()) and all the objects with Deseo = artist but I want the objects with the two queries together:
User = Parse.User.current()) and Deseo = artist
You've actually got it setup correctly to do an AND query. The problem (assuming that your data structure is setup properly) is that your User field is a Pointer to the User table. Therefore, you need to query for a User equal to the pointer, as opposed to a User equal to Parse.User.current() which will return a string. Something like the following:
var userPointer = {
__type: 'Pointer',
className: 'User',
objectId: Parse.User.current().id
}
queryDeseo1.equalTo('User', userPointer);

Mongojs fetching data from two collections and merging the result

I am a mongodb newbie and would greatly appreciate help on this problem described below.
I have two collections "users" and "bags". The user collections scheme has {username, firstname, lastname} and the bag collection schema has {username, bagname, bagimage}.
While fetching users bags, I also want to display the firstname and lastname. My problem is that I cant seem to be able to frame a query correctly. I am using nodejs and mongojs driver. Below is my query for fetching all bags
thmConfig.db.bags.find({status: "1"}).sort({$natural:-1}, function(err, data)
{
var bagList = '{"bags":[';
if( err || !data) res.send('[{"status": "0"}]');
else data.forEach( function(innerData) {
console.log(innerData.username);
bagList += JSON.stringify(innerData)+",";
/*
This is where I would lke to also append the firstname from the
users collection
*/
});
console.log(bagList.slice(0,1));
res.write(magList.slice(0,-1));
res.end(']}');
});
I would greatly appreciate any help or pointers about this. I dont have a choice about changing the driver, so I specifically want to implement this using mongojs for now.
Thanks and regards,
Titash
I don't think that you have much choice other than reading from the users collection and doing this "join" operation programmatically.
You can either read the user document per each bag (inside your loop), or read the entire users collection into an object in advance, and do lookups by username
You could use the $in operator for that.
Pseudo-code(ish):
// get an array of bags matching your query
db.bags.find({status: "1"}).sort({$natural:-1}, function(err, bags) {
// get a list of usernames from the bags:
var usernames = bags.map(function(bag) { return bag.username; });
// perform query on user table: find all users for which we have a bag
db.users.find({ username : { $in : usernames } }, function(err, users) {
// create a mapping of username -> first name for easy lookup
var usernames = {};
users.forEach(function(user) {
usernames[user.username] = user.firstname;
});
// map first names to bags
bags.forEach(function(bag) {
bag.firstname = usernames[bag.username];
});
// done: return it as JSON (no need to build a JSON string ourselves)
res.send({ bags : bags });
});
});

Categories