Query a subobject's property in a mongodb collection in meteor - javascript

I want to search names in a guest list array that may contain multiple guest objects. This array of objects is stored among other properties in a mongo db collection named "Guests" in my meteor project .
SimpleSchema snippet:
guestList: {
type: [Object],
label: "Guest List"
}
example guest object:
var newGuest = [{
firstName: "John",
lastName: "Doe"
},
{
firstname: "Jane",
lastName: "Doe"
}];
It is being inserted successfully against the SimpleSchema, what I need help with now is how I can search the names if my complete object looks something like this is the collection?
{
guestList: newGuests,
address: "123 4th St. NE",
phone: "555-555-5555",
email: "jon#doe.com"
}
Now let's say I have multiple entries with possible multiple guests within each guestList property but I want to get the entry that has the firstName of "Jane" in its guestList property.
I've tried Guests.find({ guestList: { firstName : "Jane" } }).fetch(); but I'm not getting any results.
I also tried Guests.find({guestList[0].firstName: "Jane"}).fetch(); with no results as well.
Any help would be greatly appreciated!

It sounds like what you are looking for is the $elemMatch query operator. Take a look at how to use it here too. I suggest writing your query like so:
Guests.find({
guestList: {
$elemMatch: {
firstName: 'Jane'
}
}
});
The reason why you would not use the first query that you specified is because it is trying to match on a single embedded document rather than on an array of documents. Also, the reason why you would not use the second query that you specified is because it is trying to match only on the first embedded document in an array of documents, but obviously you would want to check all of the embedded documents in an array.

$elemMatch
Guests.find({ guestList: { $elemMatch: { firstName: "Jane" }}});

Related

Removing key in a JSON object but want to keep the original

I am trying to delete a key in variable a. However, i still want to keep the original variable value for another purpose. But somehow its alway overwrite the initial a.
This is the code that i wrote:
let a = [
{ firstName: 'Tony', lastName: 'Stack' },
{ firstName: 'Iron', lastName: 'Man' }
];
console.log('before',a);
delete a[0].firstName;
console.log('after',a);
Output:
I am expecting the first console.log will be printing out the initial value.
It's just confuse myself. I feel like i must have missed some knowledge here. Appreciate for any help. Thanks
You can use map and spread operator like below
let a = [
{ firstName: 'Tony', lastName: 'Stack' },
{ firstName: 'Iron', lastName: 'Man' }
];
let removed = a.map(({firstName, ...lastName}) => lastName);
console.log('before:',a)
console.log('after:', removed)
Well your question has two parts. First, the console.log showing the same value before and after. What happens is, Chrome's console doesn't like to keep track of complicated data like objects. So, when you log the variables with the console closed, Chrome will only remember the variable. Then, when you open the console it will read that variable and display it in the logs. However, if you leave the console open and refresh the page you should see the correct values being printed.
The second part, storing the object to use it for later, requires something known as deep cloning. Here is the reason why that is required and here is a post detailing how to do it.
Your code is working correctly. Refer here for a full answer. You can verify your answer by logging the firstName instead of the whole object.
let a = [
{ firstName: 'Tony', lastName: 'Stack' },
{ firstName: 'Iron', lastName: 'Man' }
];
console.log('before',a[0].firstName);
delete a[0].firstName;
console.log('after',a[0].firstName);
let a = [
{ firstName: 'Tony', lastName: 'Stark' },
{ firstName: 'Iron', lastName: 'Man' }
];
let b= {...a} // use spread operator to clone an array
console.log('before',a);
delete b[0].firstName;
console.log('after',b);

Javascript key array by object and aggregate duplicates

I retrieve a list of an order object that comes back as array [Orders], this list can be of any size. Each order object is structured as follows. I am trying to extract the customer from the order as essentially a key and group the orders by each customer.
order: {
details: {
price: ""
}
customer: {
name: "blah blah"
email: "blah#gmail.com"
}
}
I need to figure out what the best way to group every order to a specific customer. Ensuring that if multiple orders come back for the same customer they are it ignores duplicates and still adds the orders to an array belonging to each customer. The ideal output would be
customer: {
name: "Blah Blah",
email: "blah#gmail.com",
orders: [Orders]
}
This probably could be found by searching around stack overflow for how to group an array of items, and is probably duplicated...
But, something like this should work for you, assuming that you want to group customers by email.
var result = orders.reduce(customers, order => {
// comparing customers by email
var customer = customers.find(c => c.email === order.customer.email);
if (!customer) {
customer = {
name: order.customer.name,
email: order.customer.email,
orders: [ order ]
};
// or use spread syntax, if you have that available
// customer = { ...order.customer, orders: [ order ] }
customers.push(customer);
} else {
customer.orders.push(order);
}
}, []);

Is there a good framework or approach for restructuring JavaScript objects?

I am writing an application in Node.js. I need to convert JavaScript objects returned from my database layer to JavaScript objects that I need to return from my REST service. I may need to add or remove certain properties or perhaps flatten out some structures. For example, here's a User object returned from the database layer:
{
"id": 1234,
"username": "jsmith",
"person": {
"first_name": "John",
"last_name": "Smith"
}
}
The object that I want to return from the REST layer is
{
"_links": {
"self": { "href": "/users/jsmith" },
},
"username": "jsmith",
"firstName": "John",
"lastName": "Smith"
}
Here are the changes:
"id" property is removed
"links" section has been added
"person" object has been flattened out to the parent object
"first_name" and "last_name" properties have beed converted from snake_case to camelCase
I could obviously hand-code each one of these transformations, but that would be very inefficient and error prone. Do you know of any framework or approach that would ease this pain?
P.S. I am essentially looking for something similar to the Java framework called dozer.
You will need a custom function to convert the object returned from the DB before pushing them to the RESTAPI.
An example:
var dbObject = db.query(...); //this is what you get from your DB query
//Here is your REST API object that you will send back
var restObject = (function(obj){
var link = {
self: {
href: "/users/" + obj.username
}
};
var username = obj.username;
var firstname = obj.person.first_name;
var lastname = obj.person.last_name;
return JSON.stringify({
_links: link,
username: username,
firstName: firstname,
lastName: lastname
})
})(dbObject);
Obviously, this can be cleaned up/customized to fit your code (e.g: your DB query might be asynchronous, so the restObject will need to reflect that). Also, asssuming your DB sends back a JSON object, you will need to account for that.

mongodb aggregate with find features

I have a model similar to this one:
{
email: String,
name: String,
role: String,
location: {
country: String,
city: String
},
contacts: {
email: String,
phone: String
}
}
I need to show in my view the entire users information but I wish to include also how many users from a country there are.
Using aggregate I don't know how to get the full user over the groups I create.
So at the moment what I'm doing is this:
User.find({}, function(err, users) {
User.aggregate([
{ $group: { _id: { country: '$location.country' }, count: { $sum: 1 }}}
], function(err, results) {
res.render('home', {
users: users,
countries: results
});
});
});
As you can see I'm using Find and then aggregate to get both the information I need... but I'm pretty sure there is a way to get it using only aggregate but I can not find how to do that...
If you need to accumulate the entire user information for each group, then you need to use the $push operator for accumulation and the $$ROOT system variable to access the entire user info.
User.aggregate([
{$group:{"_id":{"country":"$location.country"},
"users":{$push:"$$ROOT"},
"count":{$sum:1}}}
],callback)
In case you would want to accumulate only specific fields of the user information document, you could just push the required fields like:
User.aggregate([
{$group:{"_id":{"country":"$location.country"},
"users":{$push:{"email":"$email","name":"$name"}},
"count":{$sum:1}}}
],callback)

How can I count all dupe values in a JSON collection?

I would like to count all the companies in the following JSON string. I was first planning on doing it manually with loops but it seems like this is a good chance for me to learn to use map/reduce... How can return something that returns {company: 2}?
[
{
_id: '123',
company: 'Acme'
}
{
_id: '123',
company: 'Innatrode'
}
{
_id: '123',
company: 'Acme'
}
]
If you want to get the number of unique company names, then
use _.pluck to get the company attribute out of the list of company objects
Find the unique values out of them with _.uniq, which will return an array.
Compose a new object with the key `com
console.log({company: _.uniq(_.pluck(companies, "company")).length});
# { company: 2 }

Categories

Resources