How to query data in a flattened Firebase structure? - angularjs

I'm trying to create database for a real estate agency with Firebase. I decide to create a flatten database but I need some help..
(I'm using AngularJS)
Here is a sample of the database :
"city" : {
"Montpellier" : {
"xx2" : true,
"xx3" : true
},
"Teyran" : {
"xx1" : true
}
},
"owners" : {
"xxx1" : {
"lastname" : "Duparc",
"name" : "Jean"
},
"xxx2" : {
"lastname" : "Dupont",
"name" : "Henry"
},
"xxx3" : {
"lastname" : "Wood",
"name" : "John"
}
},
"prices" : {
"xxx1" : 405000,
"xxx2" : 100000,
"xxx3" : 122000
},
"type" : {
"appartment" : {
"xx2" : true
},
"home" : {
"xx1" : true
},
"land" : {
"xx3" : true
}
}
XX1, XX2, XX3 is the refs for each product.
In this database we see that in node Type, there is :
one home(house) : XX1
one apartment : XX2
one land : XX3
The question is : What if I want to list each product with type : Apartment?
Then if I'm able to get the ref of each Apartment, how can I construct the details for this product ?
I mean how can I get the name, last name of the owners, price, city, etc ?

What you've shown in your data structure are the indexes.
You'll typically also have a list with the master copy for each property:
"properties": {
"xx1": {
"city": "Teyran",
"owner": "Jean Duparc",
"price": 405000,
"type": "home",
},
"xx2": {
"city": "Montpellier",
"owner": "Henry Dupont",
"price": 100000,
"type": "apartment",
},
"xx3": {
"city": "Montpellier",
"owner": "John Wood",
"price": 122000,
"type": "land",
}
}
Now with our indexes and the above structure, you can for example look up the apartments with:
ref.child('type').child('apartment').on('value', function(keys) {
keys.forEach(function(keySnapshot) {
ref.child('properties').child(keySnapshot.ref().key()).once('value', function(propertySnapshot) {
console.log(propertySnapshot.val());
});
});
})
To update a property, you'd use a multi-location update. For example to update the owner of xx1:
var updates = {};
updates['/properties/xx1'] = property;
updates['/owners/Jean Duparc/'+id] = null;
updates['/owners/Runfast Webmaster/'+id] = true;
ref.update(updates);

Related

Update array value for multiple documents in mongo db

"ParentType" : {
"Food" : null,
"Inventory" : [
{
"InvId":"5ea11c6569fdbb3728133c4c"
"Unit" : "",
"Price" :5.0
},
{
"InvId":"5ea11c6569fdbb3728133c4d"
"Unit" : "Liter",
"Price" :10.0
},
{
"InvId":"5ea11c6569fdbb3728133c4e"
"Unit" : "",
"Price" :12.0
}
]
}
I need to update Unit "" to Number for all elements in array that matches the criteria.
I tried writing a query as below but it doesn't seem to work right. Pls let me know the correct mongo db script
db.Inv.update(
{ ParentType.Inventory.$[element].Unit: ""},
{ $set: {"ParentType.Inventory.$[element].Unit": "Number"} },
{ arrayFilters: [{"element.Unit": ""}] }
);

How to remove a document inside an array in mongodb using $pull

I have the following document structure
{
"_id" : ObjectId("5ffef283f1f06ff8524aa2c2"),
"applicationName" : "TestApp",
"pName" : "",
"environments" : [],
"stages" : [],
"createdAt" : ISODate("2021-01-15T09:51:35.546Z"),
"workflows" : [
[
{
"pName" : "Test1",
"wName" : "TestApp_Test1",
"agent" : ""
},
{
"pName" : "Test2",
"wName" : "TestApp_Test2",
"agent" : ""
}
],
[
{
"pName" : "Test1",
"wName" : "TestApp_Test1",
"agent" : ""
}
]
],
"updatedAt" : Date(-62135596800000)
}
I wish to remove the occurrences of
{
"pName" : "Test1",
"wName" : "TestApp_Test1",
"agent" : ""
}
The resultant document should look like
{
"_id" : ObjectId("5ffef283f1f06ff8524aa2c2"),
"applicationName" : "TestApp",
"pName" : "",
"environments" : [],
"stages" : [],
"createdAt" : ISODate("2021-01-15T09:51:35.546Z"),
"workflows" : [
[
{
"pName" : "Test2",
"wName" : "TestApp_Test2",
"agent" : ""
}
]
],
"updatedAt" : Date(-62135596800000)
}
I've tried the below mongo query
db.getCollection('workflows').update({_id:ObjectId('5ffef283f1f06ff8524aa2c2')},
{$pull:{workflows: { $elemMatch: {pipelineName: 'Test1'}}}} )
This is removing all the documents from workflows field including Test2 since Test1 is matched.
How can we remove only the entries for Test1 and keep the others?
You can do it using the positional operator "$[]" :
db.getCollection('workflows').update({_id: ObjectId("5ffef283f1f06ff8524aa2c2") }, {$pull: {"workflows.$[]":{pName:"Test1" } } } )
but the schema looks abit strange and after the update you will have empty arrays inside workflows if all elements got deleted in the sub-array.
To fix the empty sub-arrays you will need to perform second operation to remove them:
db.getCollection('workflows').update({_id: ObjectId("5ffef283f1f06ff8524aa2c2") }, {$pull: {"workflows":[] } } )
You cannot use $elemMatch as it returns the first matching element in the array.
I am not sure there is another best way to do this with the provided schema design.
play
db.collection.aggregate({
"$unwind": "$workflows"
},
{
"$unwind": "$workflows"
},
{
"$match": {
"workflows.pName": {
"$ne": "Test1"
}
}
},
{
"$group": {
"_id": "$_id",
workflows: {
$push: "$workflows"
},
applicationName: {
"$first": "$applicationName"
}
}
},
{
"$group": {
"_id": "$_id",
workflows: {
$push: "$workflows"
},
applicationName: {
"$first": "$applicationName"
}
}
})
unwind twice required to de-normalize the data
match to filter out the unnecessary doc
group twice required to bring the required output
You can save this to a collection using $out as last stage.

Update an element of an Array in a Document in MongoDB with Mongoose

I have a MongoDB database whith a collection with this structure:
{
"_id" : ObjectId("5b670eefe94672265ca59428"),
"duration" : {
"start" : ISODate("2018-09-01T00:00:00.000Z"),
"end" : ISODate("2018-09-01T00:00:00.000Z")
},
"title" : "Example title.",
"description" : "<p>Hi example!</p>",
"slug" : "title",
"insertDate" : ISODate("2018-08-05T14:51:27.194Z"),
"webData" : [
{
"_id" : ObjectId("5bb1f082931c536950ade361"),
"webCode" : "be_mx",
"categories" : [
{
"_id" : ObjectId("3sdf43f34543et35tret435"),
"name" : "Category 1",
"webCode" : "be_mx",
"slug" : "category-1"
},{
"_id" : ObjectId("3sdf43f34543et35tretert"),
"name" : "Category 2",
"webCode" : "be_mx",
"slug" : "category-2"
}
]
}
],
"__v" : 6,
"lastEditionDate" : ISODate("2018-10-01T10:01:38.889Z")
}
I want to update all documents from this collection that has a categorie with a _id = "3sdf43f34543et35tret435" (in this example the "Category 1"), and I want to update this element category setting, for example, the slug to "category-3".
I tried to do that with this code:
Collection.update({
"webData.categories": {
$elemMatch: {
_id: ObjectId("3sdf43f34543et35tret435")
}
}
}, {
$set: {
webData: {
"categories.$.slug": "category-3"
}
}
}, {
multi: true
}, (err, res) => {
if (err) { console.log(err); }
console.log(res);
});
When I execute that, all the documents that have this category are edited but it's wrong because all the related categories are deleted.
Can you help me with this operation?
Thank you!
EDITED:
When I execute in my DB this query:
db.getCollection("scholarships").update({},
{ '$set': { 'webData.[].categories.$[category].slug': "nana" } },
{ multi: true, arrayFilters: [{ 'category._id': ObjectId("5b719d821f3f1131ec4524f6") }] })
Using in this time an arrayFilter, I receive this error:
The path 'webData.[].categories' must exist in the document in order to apply array updates."

Conditionally remove Subdocument nested inside array of document MongoDB

I have a collection with document like this:
{
"_id" : "ABC",
"Name" : "Rajesh",
"createstmp" : ISODate("2015-06-22T17:09:16.705Z"),
"updstmp" : ISODate("2015-06-22T19:31:53.527Z"),
"AvgValue" : "65",
"PreValues" : [
{
"Date" : 20150709,
"Rate" : [
{
"Time" : 1566,
"value" : 60
},
{
"Time" : 1500,
"value" : 400
},
{
"Time" : 1400,
"value" : 100
},
{
"Time" : 1500,
"value" : 103
}
]
}
]
}
I want to remove the duplicate doc for a particular Date value
eg If Time value is 1500, I need to pull the document and push it the new value for (Value) in single bulk operation.
Here is my query
bulk.find({ "_id":"ABC" })
.update(
{
"_id": "ABC",
"PreValues": { "Date": 20150709 }
},
{
$pu‌​ll: { "PreValues": { "Rate": { "Time": 1000 } } }
}
);
bulk.find({ "_id":"ABC" })
.update(
{ "_id": "ABC","PreValues": { "Date": 20150709 }},
{ $pu‌​sh : {
"PreValues": { "Rate": { "Time": 1000,"Rating": 100 }}
}}
);
bulk.execute();
It's not a great idea to have nested arrays since the only thing you will ever be able to do atomically is $push or $pull. See the positional $ operator for details on why "nested arrays" are not good here, but basically you can only ever match the position of the "outer" array element.
And that is basically what you are missing here, and of course the proper "dot notation" for accessing the elements:
var bulk = db.ABA.initializeOrderedBulkOp();
bulk.find({ "_id": "ABC", "PreValues.Date": 20150709 })
.updateOne({ "$pull": { "PreValues.$.Rate": { "Time": 1500 } } })
bulk.find({ "_id": "ABC", "PreValues.Date": 20150709 })
.updateOne({ "$push": { "PreValues.$.Rate": { "Time": 1500, "Rating": 100 } } })
bulk.execute();
Which alters the document like so:
{
"_id" : "ABC",
"Name" : "Rajesh",
"createstmp" : ISODate("2015-06-22T17:09:16.705Z"),
"updstmp" : ISODate("2015-06-22T19:31:53.527Z"),
"AvgValue" : "65",
"PreValues" : [
{
"Date" : 20150709,
"Rate" : [
{
"Time" : 1566,
"value" : 60
},
{
"Time" : 1400,
"value" : 100
},
{
"Time" : 1500,
"Rating" : 100
}
]
}
]
}
That is the correct syntax for both statements there and sends both requests to the server at the same time with a single response.
Note that you need to inclide in the .find() query a field from the outer array to match. This is so the positional $ operator is populated with the matched index of that element and the operator knows which array element to act upon.

Mongodb - Query Array of Objects, but only return one property

I don't think this is a duplicate, but please correct me if I'm wrong. Anyway, I would like to return only "apple" and the customer member role that matches the user's object email address. I am using $elemMatch, but that returns the whole customer object, I only want the "member" property, that's it.
{
"_id" : ObjectId("54d24e5df2878d40192beabd"),
"apple" : "yes",
"orange" : "yes",
"customers" : [
{
"name" : "Jay Smith",
"email" : "jaysmith#example.com",
"member" : "silver",
},
{
"name" : "Sarah Carter",
"email" : "sarahcarter#example.com",
"member" : "gold",
},
{
"name" : "Jack Whatever",
"email" : "jackwhatever#example.com",
"member" : "gold",
},
]
}
Ideal result back would be:
{
"_id" : ObjectId("54d24e5df2878d40192beabd"),
"apple" : "yes",
"member" : "gold"
}
or even this would suffice:
{
"_id" : ObjectId("54d24e5df2878d40192beabd"),
"apple" : "yes",
"orange" : "yes",
"customers" : [
{"member" : "gold"}
]
}
This is currently what I have:
ItemsModel.find({ _id: { $in: _.pluck(user.items, 'itemId') }, active: true},
{apple: 1, customers: {$elemMatch: {email: user.email}} },
function(error, items) {
if (error) { return next(error); }
req.payload = {};
req.payload.items = items;
next();
});
Any help would be really appreciated. Is this even possible? Thanks!
ItemsModel.aggregate([
{ $unwind: '$customers' },
{ $match: { _id: { $in: _.pluck(user.items, 'itemId'), 'customers.email': user.email } },
{ $project : { _id:1 , apple:1, member:'$customers.member' }}
], function(err, res){
// rest of your code here
})
Will give you
{
"_id" : ObjectId("54d24e5df2878d40192beabd"),
"apple" : "yes",
"member" : "gold"
}

Resources