So I am making a 2D game using Firebase along with JavaScript and here is part of the saved file. They use JSON to store data.
{
"player" : {
"github:123123" : {
"email" : "tester#gmail.com",
"inventory" : {
"slot_1" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_10" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_11" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_12" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_13" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_14" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_15" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_16" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_17" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_18" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_19" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_2" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_20" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_3" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_4" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_5" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_6" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_7" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_8" : {
"item_id" : 0,
"item_qty" : 0
},
"slot_9" : {
"item_id" : 0,
"item_qty" : 0
}
},
"lowercase" : "test",
"map" : 1,
"member_level" : 2,
"signed_up" : 1437261263536,
"uid" : "github:616320",
"username" : "Test",
"version" : "1.0.0",
"x" : 50,
"y" : 20
}
}
}
As you can see, the problem lies how the inventory is structured. Is there a better way to structure so it's nicer and neat? I have read up on the Structuring Data docs on Firebase but I would appreciate your input.
This could also follow suit for not just inventory but banks and wherever large quanities of slots for items are needed in the game.
Thanks.
Well. Your version should work, however I would suggest the following structure:
{
"email" : "tester#gmail.com",
"inventory" : [{
"id": 0,
"amount": 0
},{
"id": 0,
"amount": 0
},{
"id": 0,
"amount": 0
},{
"id": 0,
"amount": 0
}],
"lowercase" : "test",
"map" : 1,
"memberLevel" : 2,
"signedUp" : 1437261263536,
"uid" : "github:616320",
"username" : "Test",
"version" : "1.0.0",
"x" : 50,
"y" : 20
}
Reasoning:
In JS camelCase is default for most projects, therefore I would use it here too.
You don't need the player attribute and github:* attribute if they are the only one. Safe the JSON to a database for players instead and keep one JSON per player.
The data structure of your inventory seems to be better fitting as an array, because you basically use every slot (if not, it's empty) and want to access it by the slot id.
If the subobject you describe is in the inventory array there is no need to call every property item, because that's obvious.
Related
I want to find and remove the value, where my id is "5cc6d9737760963ea07de411"
my data:
[
{
"products" : [ {
"id" : "5cc6d9737760963ea07de411",
"quantity" : 1,
"totalPrice" : 100,
},
{
"id" : "5cc6d9737760963ea07de412",
"quantity" : 2,
"totalPrice" : 200,
}
],
"isCompleted" : false,
"_id" : "5cc7e4096d7c2c1f03570a2f"
},
{
"products" : [{
"id" : "5cc6d9737760963ea07de414",
"quantity" : 1,
"totalPrice" : 100,
},
{
"id" : "5cc6d9737760963ea07de4133",
"quantity" : 2,
"totalPrice" : 200,
}
],
"isCompleted" : false,
"_id" : "5cc7e4096d7c2c1f03570a2f"
}
]
i tried:
Schema.findOneAndUpdate({"products.id": "5cc6d9737760963ea07de411"},
{ $pull: {"products.$.id": "5cc6d9737760963ea07de411" })
but it's not working.
Now you don't need to use .dot notation. Instead you need to use "absolute" object structures:
Schema.findOneAndUpdate(
{ "products.id": "5cc6d9737760963ea07de411" },
{ "$pull": { "products": { "id": "5cc6d9737760963ea07de411" }}}
)
I have a dataset like this:
{
"_id" : ObjectId("5a4c6fb6993a721b3479a27e"),
"score" : 8.3,
"page" : "message",
"lastmodified" : ISODate("2018-01-03T06:49:19.232Z"),
"createdate" : ISODate("2018-01-03T05:52:54.446Z"),
"slug" : [
"#APPLE"
],
"__v" : 0
},
{
"_id" : ObjectId("5a4c6fb6993a721b3479a27e"),
"score" : 9.3,
"page" : "#BANANA",
"lastmodified" : ISODate("2018-01-03T06:49:19.232Z"),
"createdate" : ISODate("2018-01-03T05:52:54.446Z"),
"slug" : [
"#APPLE"
],
"__v" : 0
}
{
"_id" : ObjectId("5a4c6fb6993a721b3479a27e"),
"score" : 5.3,
"page" : "#BANANA",
"lastmodified" : ISODate("2018-01-03T06:49:19.232Z"),
"createdate" : ISODate("2018-01-03T05:52:54.446Z"),
"slug" : [
"#BANANA"
],
"__v" : 0
}
Now I want to calculate the sum of score according to my Filter Like this:
#APPLE: 8.3+9.3 = 17.6 i.e #APPLE: 17.6,
#BANANA: 9.3+5.3 = 14.6 i.e #BANANA: 14.6
So for this I have to pick only last 1 hour data rather than picking the whole database
. So my query is like this
var newTime = new Date();
newTime.setHours( newTime.getHours() - 1 );
db.Test.find({"lastmodified":{$gt: newTime}})
so By this I can get only last 1 hour value. Now I am confuse that how i can do sum with filter. I also attached filter query i.e
db.Test.find({"lastmodified":{$gt: newTime}}, {$or: [{slug: {$in: ['#APPLE']}}, {page: '#APPLE'}]})
But it does not give anything. any help is appreciated
Try this aggregate query...
db.tests.aggregate([{
"$unwind": "$slug"
},
{
"$group": {
"_id": "$slug",
"totalScore": {
"$sum": "$score"
}
}
}
]);
Result:
{
"_id" : "#BANANA",
"totalScore" : 5.3
}
{
"_id" : "#APPLE",
"totalScore" : 17.6
}
I am using javascript - mongoose. (beginner)
Trying to calculate average of 'timeSpend' for each fields
{
"_id" : ObjectId("5a2cca1c44ac67e8d5b8d2ff"),
"total" : {
"timeSpend" : "20"
},
"name_1" : {
"timeSpend" : 9,
"test" : "fail"
},
"name_2" : {
"timeSpend" : "11",
"test" : "fail"
},
"name_3" : {
"timeSpend" : "8",
"test" : "fail"
}
"__v" : 0
},
{
"_id" : ObjectId("5a2cca1c44ac67e8d5b8d2ff"),
"total" : {
"timeSpend" : "10"
},
"name_1" : {
"timeSpend" : 10,
"test" : "fail"
},
"name_2" : {
"timeSpend" : "5",
"test" : "fail"
},
"name_3" : {
"timeSpend" : "2",
"test" : "fail"
}
"__v" : 0
}
.... more documents...(every 10 minutes, new document will be saved)
I am trying to calculate average 'timeSpend' for each fields
Example :
{
total : 15,
name_1 : 9.5,
name_2 : 8,
name_3 : 5
}
I tried
(mongoose Schema).find({}).select('name_1' : 1, '_id':0)
then calculate average using loop, but I think it will be too expensive computing since document will be updated every 10 minutes (have to update average every 10 mins)
You can achieve that with a simple mongodb aggregation.
You basically have to group by null to get one document in the end, and use the $avg aggregation operator to get all averages.
Following would work
collection.aggregate([{
$group: {
_id: null,
total: {
$avg: "$total.timeSpend"
},
name_1: {
$avg: "$name_1.timeSpend"
},
name_2: {
$avg: "$name_2.timeSpend"
},
name_3: {
$avg: "$name_3.timeSpend"
}
}
}])
Ok, I have this collection:
{
"_id" : ObjectId("59baa8af86e5df3984674639"),
"centralPath" : "C:\\Users\\konrad.sobon\\OneDrive - HOK\\GoogleDrive\\Work\\DynamoWork\\142_SeatManifestGenerator\\RVT2018\\CBUEC_HOK_IN-central.rvt",
"totalFamilies" : 31,
"unusedFamilies" : 18,
"oversizedFamilies" : 0,
"inPlaceFamilies" : 0,
"createdBy" : "konrad.sobon",
"createdOn" : ISODate("2017-09-14T20:19:09.525Z"),
"families" : [
{
"name" : "Spot Elevation - Target Filled_HOK_I",
"size" : "1.2Mb",
"sizeValue" : 1200000,
"instances" : 0,
"elementId" : 6158,
"isFailingChecks" : true,
"isDeleted" : false,
"_id" : ObjectId("59bae43d2720015998392905"),
"tasks" : [],
"parametersCount" : 0,
"nestedFamilyCount" : 1,
"voidCount" : 0,
"refPlaneCount" : 2,
"arrayCount" : 0
},
{
"name" : "Section Head - Filled_HOK_I",
"size" : "140kb",
"sizeValue" : 145760,
"instances" : 0,
"elementId" : 8762,
"isFailingChecks" : true,
"isDeleted" : false,
"_id" : ObjectId("59bae43d2720015998392904"),
"tasks" : [],
"parametersCount" : 0,
"nestedFamilyCount" : 1,
"voidCount" : 0,
"refPlaneCount" : 3,
"arrayCount" : 0
},
{
"name" : "Railing Tag_HOK_I",
"size" : "244kb",
"sizeValue" : 249856,
"instances" : 0,
"elementId" : 12426,
"isFailingChecks" : true,
"isDeleted" : false,
"_id" : ObjectId("59bae43d2720015998392903"),
"tasks" : [],
"parametersCount" : 3,
"nestedFamilyCount" : 1,
"voidCount" : 0,
"refPlaneCount" : 2,
"arrayCount" : 0
},
{
"name" : "Fixed",
"size" : "316kb",
"sizeValue" : 323584,
"instances" : 0,
"elementId" : 3499132,
"isFailingChecks" : true,
"isDeleted" : false,
"_id" : ObjectId("59bae43d27200159983928e7"),
"tasks" : [],
"parametersCount" : 4,
"nestedFamilyCount" : 2,
"voidCount" : 0,
"refPlaneCount" : 18,
"arrayCount" : 0
}
],
"__v" : 0
}
What I am trying to do is send a request to update certain "families" in that collection. I have an array of these Family objects looking like this:
{"key": [
{
"name" : "New Spot Elevation - Target Filled_HOK_I",
"size" : "1.2Mb",
"sizeValue" : 1200000,
"instances" : 0,
"elementId" : 6158,
"isFailingChecks" : true,
"isDeleted" : false,
"Id" : "59bae43d2720015998392905",
"tasks" : [],
"parametersCount" : 0,
"nestedFamilyCount" : 1,
"voidCount" : 0,
"refPlaneCount" : 2,
"arrayCount" : 0
},
{
"name" : "New Section Head - Filled_HOK_I",
"size" : "140kb",
"sizeValue" : 145760,
"instances" : 0,
"elementId" : 8762,
"isFailingChecks" : true,
"isDeleted" : false,
"Id" : "59bae43d2720015998392904",
"tasks" : [],
"parametersCount" : 0,
"nestedFamilyCount" : 1,
"voidCount" : 0,
"refPlaneCount" : 3,
"arrayCount" : 0
}
]}
Now, I need to be able to find and update each of the specified families. I thought that i can just iterate over the incoming array (I am sending it in a req.body), and then make an array of Ids that would need to be updated so i can use the $in operator in mongo. After that, i thought that I can use the id, to retrieve the properties that I am interested and just use $set to get them updated. My attempt here:
module.exports.updateMultipleFamilies = function (req, res) {
var id = req.params.id;
var famIds = []; // [ObjectId]
var newFamilies = {}; // {"id_string" : family}
for(var key in req.body) {
if(req.body.hasOwnProperty(key)){
for(var i = 0; i < req.body[key].length; i++){
var family = req.body[key][i];
newFamilies[family.Id] = family;
famIds.push(mongoose.Types.ObjectId(family.Id));
}
}
}
Families
.updateMany(
{_id: id, 'families._id': {$in: famIds}},
{$set: {'name': newFamilies["current_document_id_help"].name}}, function(err, result){
if(err) {
res
.status(400)
.json(err);
} else {
res
.status(202)
.json(result);
}
}
)
};
Edit:
So i tried a different approach with the bulkWrite call. It doesn't give me errors but it also doesn't update anything. Any ideas why?
module.exports.updateMultipleFamilies1 = function (req, res) {
var id = req.params.id;
var bulkOps = [];
for(var key in req.body) {
if(req.body.hasOwnProperty(key)){
bulkOps = req.body[key].map(function(item){
return {
'updateOne': {
'filter': {'_id': id, 'families._id': mongoose.Types.ObjectId(item.Id)},
'update': {'$set': {'families.$.name': item.name}},
'upsert': false
}
}
})
}
}
Families.collection
.bulkWrite(
bulkOps,
{'ordered': true, w:1}, function(err, result){
if(err) {
res
.status(400)
.json(err);
} else {
res
.status(202)
.json(result);
}
})
};
you need to take the families array , change the code in the app and then update the families array again.
or you can try do {$set:{'families.$.name':newFamilies["current_document_id_help"].name}
}
but im not sure if that wont update all you families
first solution:
var id = req.params.id;
yourCollation.findById(id,function(err, doc){
if(req.body.key && req.body.key.constructor === Array){
for(var i = 0; i < req.body.key.length; i++){
for(var x in doc.families ){
if(family.id === doc.families[x].id){
doc.families[x] = family;
}
}
}
}
doc.save()
})
I am trying to use the $multiply operator in MongoDB.
STEP 1
db.message1064sd_00011_3744.aggregate([
{$project : {
"prices.00026" : 1,
priceReal : {
price : "$prices.00026",
}
}},
{ $match : { "priceReal.price" : {$gt : 30 } } },
{ $limit : 1 }
])
I am getting the results
{
"result" : [
{
"_id" : "54884_00011_001",
"prices" : {
"00026" : 34.43
},
"priceReal" : {
"price" : 34.43
}
}
],
"ok" : 1
}
STEP 2
But, when I use $multiply, I get
$multiply only supports numeric types, not array
db.message1064sd_00011_3744.aggregate([
{$project : {
"prices.00026" : 1,
priceReal : {
price : { $multiply : ["$prices.00026", 1 ] },
}
}},
{ $match : { "priceReal.price" : {$gt : 30 } } },
{ $limit : 1 }
])
Help me anybody
Example document which I can get from db.message1064sd_00011_3744.findOne()
{
"_id" : "25906_00011_001",
"Message_ID" : 25906,
"Subdivision_ID" : 3747,
"Sub_Class_ID" : 6300,
"Checked" : 1,
"Nomencl_ID" : "10000014597",
"manufacturer_ID" : "П1170",
"disableIfZero" : 0,
"Discontinued" : 0,
"New" : 0,
"Nomencl_Group_ID" : 28,
"Nalichie" : "Мало",
"sort" : 99,
"Warehouse_ID" : "00011",
"ParentWarehouse_ID" : "00011",
"Kachestvo" : "001",
"Svobod_Nalichie" : "10",
"Svobod_sort" : 10,
"character" : [],
"prices" : {
"00014" : 1.51,
"00015" : 1.45,
"00016" : 1.41,
"00017" : 1.38,
"00018" : 1.35,
"00019" : 1.33,
"00021" : 1.31,
"00022" : 1.29,
"00023" : 1.28,
"00024" : 1.27,
"00025" : 1.25,
"00026" : 1.24
},
"price" : {
"Curr_ID" : 840,
"ChangePriceTime" : "2017-01-22 19:18:21",
"PriceUpDown" : "up",
"callPrice" : 0,
"Price_Value_RODP" : 1.24,
"Price_Value_RUR" : 72.04000000000001
},
"sName" : "чип epson m2300{m2400{mx20 8k (elp, китай)",
"sNomencl_ID" : "10000014597",
"sNomencl_Articul_Proizvod" : "elp-ch-e2300-8k",
"sItemID" : "elp-ch-e2300-8k",
"EnglishName" : "cZ277",
"begin_vl" : 121,
"Hidden_URL" : "/netshop/cZ079/cZ270/cZ277/",
"Checked_Subdivision" : 1
}
In case you want to ensure that only data from a certain data type enters your result set, for example in an aggregate query, you can add the following filter to the match:
{$match: {
// ... your query
, "priceReal.price": { $type : "double" }
}