MongoDB Query filtering on SubArray IDs - mongodb

Suppose I have the 3 collections in MongoDB below. Assume the "commitment_id" value is the Object_ID of "My Commitment" and the "id" values in the funds array refer to "My Fund" and "His Fund". How do I get the list of funds referred to in the funds array of the commitment_attributes collection? From everything I've read it seems like I would need to loop through the cursor and get each one by one, but is there a way to do this in a query automatically?
db.commitments.insert({
commitment_nm : "My Commitment",
due_dt : "1/1/2016",
ccy: "USD"
});
db.funds.insert({
name: "My Fund",
ccy_iso_cd: "USD"
}, {
name: "His Fund",
ccy_iso_cd: "EUR",
})
db.commitment_attributes.insert({
"commitment_id": ObjectId("56fdd7e371d53780e4a63d58"),
"attribute_nm": "Original Commitment",
"effective_dt": "1/10/2016",
"funds": [
{
"id": ObjectId("56fdd78c71d53780e4a63d57"),
"amount": 1000
},
{
"id": ObjectId("56fdd78c71d53780e4a63d57"),
"amount": 500
}
]
})
var commitment = db.commitments.findOne({commitment_nm: "My Commitment"})
var attribute = db.commitment_attribtues.findOne({"commitment_id" : commitment._id});
var funds = ...... want to query for only the funds which have their ID mentioned in the attribute var

Related

MongoDB query $and that returns documents that matches all fields progressively

I am trying to query an array of cars. This is an example of my data set:
[
{
"model": "Model 3",
"location": "Canada",
"color": "green",
"engine": "1.4 turbo",
"gearbox": "automatic",
...
},
{
"model": "Model 4",
"location": "Brazil",
"color": "green",
"engine": "1.4 turbo",
"gearbox": "automatic",
...
}
]
This is my query:
Car.paginate(
{
model: new RegExp(`^${req.body.model}$`, 'i'),
color: new RegExp(`^${req.body.color}$`, 'i'),
...
},
{ offset, limit, sort: getSort(req.query.sortType), populate: ['car'] }
)
This query is using an implicit $and but that's not what I want to do. I want to return all the documents that satisfy one or more of the query but also that takes into account all queries. So, if I search for "model 1" it will return all cars that are named "model 1" and if I search for "model 1" and "black" it should return all cars that are named "model 1" and are of the color "black" (NOT all "model 1" AND all color "black").
Also, the way I am doing it right now, all fields are required to exist in my req.body. I would like for it to not require all the fields, only search with the fields it's given.
In your endpoint you would want to build the query object before making the call to paginate(). This way you can check for certain fields in the request body to determine if they should be added. It might look like this:
var query = {};
if (req.body.model) {
query.model = new RegExp(`^${req.body.model}$`, 'i');
}
if (req.body.color) {
query.color = new RegExp(`^${req.body.color}$`, 'i');
}
This way the query will only contain fields in the request body. You would then pass query to paginate() like this:
Car.paginate(
query,
{ offset, limit, sort: getSort(req.query.sortType), populate: ['car'] }
)
If there are other fields you want to include in the query by default you can add them when it is first declared.

Embedded Documents in MongoDB

I'm having trouble understanding exactly how Embedded Documents are enforced in a soft schema such as MongoDB. if given a data-model like so:
User{
UserId:
Email:
Phone:
Reviews{
Rating:
Comment:
}//End reviews
}
Does this mean every User Document has only one review or that this is the format in which all reviews will be for a User?
Perhaps a more relational model of this would be the folloiwng:
User{
UserId:
Phone:
Email:
}
Reviews{
User:<UserID>
Rating:
Comment:
}
I know using references means a slower query but I don't understand how Embedded Documents would allow for multiple reviews.
In the case of having multiple document for the same user, MongoDB adds an unique _Id to the document every time you add a new document, so this wokrks good when you are adding multiple documents for the same user and as #wdberkeley stated, MongoDB does not enforce a schema,
"User" {
"UserId": "johndoe"
"Email": "johndoe#yahoo.com"
"Phone": "555-44444"
"Review"{
"Rating": "5"
"Comment": "this is my first comment"
}
}
"User" {
"UserId": "johndoe"
"Email": "johndoe#yahoo.com"
"Phone": "555-44444"
"Review"{
"Rating": "5"
"Comment": "this is my second comment"
}
}
"User" {
"UserId": "johndoe"
"Email": "johndoe#yahoo.com"
"Phone": "555-44444"
"Review"{
"Rating": "5"
"Comment": "this is my third comment"
}
}
In the case of one document for one user with multiple reviews, this can work fine too, can always get the document and add append reviews to it and call db.update() on the document,
"User" {
"UserId": "johndoe"
"Email": "johndoe#yahoo.com"
"Phone": "555-44444"
"Reviews"{[
{
"Rating": "5"
"Comment": "this is my first comment"
},
{
"Rating": "5"
"Comment": "this is my second comment"
},
{
"Rating": "5"
"Comment": "this is my third comment"
}
]}
}
Are you talking about how this is enforced in MongoDB or in an ODM like Mongoose? For MongoDB, the answer it simple: MongoDB doesn't enforce a schema. You can have all three of the following documents in a MongoDB collection:
{
"reviews" : {
"rating" : 9001,
"comment" : "nice scenery"
}
}
{
"reviews" : [
{
"rating" : [2, 4, 5],
"comment" : 19
},
{
"rating" : -845,
"comment" : "Powerful stuff"
}
]
}
{
"reviews" : "no"
}
In an ODM that enforces a schema application side, your notation is closest to something that would mean each document should have one reviews subdocument.

Sorting by document values in couchbase and scala

I am using couchbase and I have a document (product) that looks like:
{
"id": "5fe281c3-81b6-4eb5-96a1-331ff3b37c2c",
"defaultName": "default name",
"defaultDescription": "default description",
"references": {
"configuratorId": "1",
"seekId": "1",
"hsId": "1",
"fpId": "1"
},
"tenantProducts": {
"2": {
"adminRank": 1,
"systemRank": 15,
"categories": [
"3"
]
}
},
"docType": "product"
}
I wish to get all products (this json is product) that belong to certain category, So i've created the following view:
function (doc, meta) {
if(doc.docType == "product")
{
for (var tenant in doc.tenantProducts) {
var categories = doc.tenantProducts[tenant].categories
// emit(categories, doc);
for(i=0;i<categories.length;i++)
{
emit([tenant, categories[i]], doc);
}
}
}
}
So i can run the view with keys like:
[["tenantId", "Category1"]] //Can also have: [["tenant1", "Category1"],["tenant1", "Category2"] ]
My problem is that i receive the document, but i wish to sort the documents by their admin rank and system rank, these are 2 fields that exists in the "value".
I understand that the only solution would be to add those fields to my key, determine that my key would be from now:
[["tenantId", "Category1", "systemRank", "adminRank"]]
And after i get documents, i need to sort by the 3rd and 4th parameters of the key ?
I just want to make sure i understand this right.
Thanks

MongoDB: How to update a compound item of an array ensuring no duplicates

Here below is a hypothetical Users collection where more than one address is allowed:
{
"firstName": "Joe",
"lastName": "Grey",
...
"addresses":
[
{
"name": "Default",
"street": "..."
...
},
{
"name": "Home",
"street": "..."
...
},
{
"name": "Office",
"street": "..."
...
}
]
}
Every address has a name... which should be unique – e.g. there couldn't be two addresses named Default. If I want to update let's say the address at index 1 (Home), how do I ensure the update data does not contain names Default and Office?
I guess a two-steps approach (i.e. find and then update) wouldn't be very correct since data might be updated between the find and the subsequent update operation, isn't?
var renamed = 'Office'; // from user input
var users = getUserMongoCollection();
users.update({_id:userId, 'addresses.name': { $ne : renamed } },
{ $set : { 'addresses.1.name' : renamed } }, function(err){
//all done!
});
Find the record by ID, and only update it if the array doesn't contain the new name.

MongoDB: How to update a complex item of an array with a new complex item

Here below is once again my hypothetical Users collection where more than one address is allowed:
{
"firstName": "Joe",
"lastName": "Grey",
...
"addresses":
[
{
"name": "Default",
"street": "...",
...,
"isDefault": true
},
{
"name": "Home",
"street": "...",
...,
"isDefault": false
},
{
"name": "Office",
"street": "...",
...,
"isDefault": false
}
]
}
Let's suppose I want to update the second address (Home) with the following new item:
{
"name": "New home",
"street": "Ruta del Sol"
},
How do I update the second item of the array with the new item, also considering that the new item might or might not provide all the fields of an address?
In this post Will shown me how to update a field at a given index, ensuring the address name remains unique. Now, instead of updating a single field, I want to update an entire item.
All you need to do is transform new json data for update . Example:
Let us assume you have new Json data with only two fields 'name' and 'isDefault' .
var newData = {"name" : "New Val","isDefault":true};
var updateData = {};
for (key in newData ) {
updateData["addresses.$."+key]=newData[key];
};
db.projectPlan.update({_id:1, 'addresses.name': 'Home'}, {$set:updateData});
var renamed = 'Office'; // from user input
var users = getUserMongoCollection();
var address = {
name: "Office,
street: "Ruta del Sol"
};
users.update({_id:userId },
{ $set : { 'addresses.1' : address } }, function(err){
//all done!
});