Mongoose Model, cleaning/parsing an Array efficiently - arrays

I am having some issues with a mongoose array, it's likely due to my lacking understanding of the library, and I can't find the exact answer I'm looking for in the docs.
For starters I have my schema and model declarations:
const gConfig = new Schema({ aList: Array, maxChanLimit: Number }), globalConfiguration = mongoose.model('globalConfig', gConfig);
And I have my command which fetches the array, parses out _id, then pushes the new item to the array, and overwrites the existing one in the database.
if((message.author.id === g.ownerID) && (g.id.toString() === tocGuild) && message.content.startsWith("!updatealist"))
{
let mc = message.content.replace("!updatealist ", "");
globalConfiguration.findOneAndUpdate({},{$push: {"aList":mc }}, { upsert: true }, function(err, data) {
if (err) return console.log(err);
var str = JSON.stringify(data); str = str.replace(RegExp(/"_id"|"__v"|'/g),""); var arr = str.split(`","`);
});
}
I feel like there has to be a better way to do this, I've tried something like this based on what I've read:
globalConfiguration.findOneAndUpdate({},{$push: {"-_id aList":mc }}
However this did not remove _id from the array. I suppose how I'm doing it is a way to do it, but I know it isn't efficient, and isn't dynamic at all, it's also extremely bulky in terms of code and could be streamlined using the library.
In practice, what is the best way to properly read an array from a model with Mongoose? How do you read from the array without the additional objects Mongoose adds by default? What is the best way to add an item to an existing model?
Any help is appreciated, thank you.

if you want to have more control over the updating process, you can do it like this, in the mongoose documents it suggest you can first query the item/document you want to update, once that document is queried and there, you can make changes to it such as if it contains an array , you can push to it or pop from it or what ever..
its in your control
so,
if((message.author.id === g.ownerID) && (g.id.toString() === tocGuild) && message.content.startsWith("!updatealist"))
{
let mc = message.content.replace("!updatealist ", "");
globalConfiguration.findOne({"your query"}, function(err, data) {
if (err) throw (err);
data.array.push("something");
data.save();// save it again with updates
var str = JSON.stringify(data); str = str.replace(RegExp(/"_id"|"__v"|'/g),""); var arr = str.split(`","`);
});
}

Related

Dapper One to Many Mapping Logic

The dapper tutorial gives this example to help a user with Multi Mapping (One to Many)
While this works I am curious why they have you store the orders in the dictionary but then in the end they use a linq.Distinct() and return from the list. It seems like it would be cleaner to just return the ordersDictionary.Values as the dictionary logic ensures no duplicates.
//Tutorial
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
Dictionary<int,Order> orderDictionary = new Dictionary<int, Order>();
List<Order> list = connection.Query<Order, OrderDetail, Order>(sql, (order, orderDetail) =>
{
if (!orderDictionary.TryGetValue(order.OrderID, out Order orderEntry))
{
orderEntry = order;
orderEntry.OrderDetails = new List<OrderDetail>();
orderDictionary.Add(orderEntry.OrderID, orderEntry);
}
orderEntry.OrderDetails.Add(orderDetail);
return orderEntry;
}, splitOn: "OrderID")
.Distinct()
.ToList();
return list;
}
//my suggestion
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
Dictionary<int,Order> orderDictionary = new Dictionary<int, Order>();
//change 1 no need to store into list here
connection.Query<Order, OrderDetail, Order>(sql, (order, orderDetail) =>
{
if (!orderDictionary.TryGetValue(order.OrderID, out Order orderEntry))
{
orderEntry = order;
orderEntry.OrderDetails = new List<OrderDetail>();
orderDictionary.Add(orderEntry.OrderID, orderEntry);
}
orderEntry.OrderDetails.Add(orderDetail);
return orderEntry;
}, splitOn: "OrderID"); //change 2 remove .Distinct().ToList()
return orderDictionary.Values.ToList(); //change 3 return dictionaryValues
}
I'm the author of this tutorial: https://dapper-tutorial.net/query#example-query-multi-mapping-one-to-many
why they have you store the orders in the dictionary
A row is returned for every OrderDetail. So you want to make sure to add the OrderDetail to the existing Order and not create a new one for every OrderDetail. The dictionary is used for performance to check if the Order has been already created or not.
it would be cleaner to just return the ordersDictionary.Values
How will your query return dictionary values?
Of course, if you are in a method such as yours, you can do
var list = orderDictionary.Values;
return list;
But how to make this Connection.Query return dictionary values? An order is returned for every row/OrderDetail, so the order will be returned multiple times.
Outside the Query, your dictionary solution works great and is even a better solution for performance, but if you want to make your Query return the distinct list of orders without using Distinct or some similar method, it's impossible.
EDIT: Answer comment
my suggestion return orderDictionary.Values.ToList(); //change 3 return dictionaryValues
Thank you for your great feedback, it's always appreciated ;)
It would be weird in a tutorial to use what the query returns when there is no relationship but use the dictionary for one to many relationships
// no relationship
var orders = conn.Query<Order>("", ...).Distinct();
// one to many relationship
conn.Query<Order, OrderDetail>("", ...);
var orders = orderDictionary.Values.ToList();
Your solution is better for performance the way you use it, there is no doubt about this. But this is how people usually use the Query method:
var orders = conn.Query("", ...).Distinct();
var activeOrders = orders.Where(x => x.IsActive).ToList();
var inactiveOrders = orders.Where(x => !x.IsActive).ToList();
They use what the Query method returns.
But again, there is nothing wrong with the way you do it, this is even better if you can do it.

Mongoose querying the array... changing the elements of the array

I am trying to remove all the elements from the array in the MongoDB database, then I insert all the new array elements.
My Model is:
const mongoose = require('mongoose');
var schema = new mongoose.Schema({
email : {
type : String
},
password : {
type : String
},
stocks : {
type : [String]
}
}, {versionKey:false}, {_id: false});
module.exports = final = mongoose.model('users', schema);
My stocks array will then have some values. I am trying to remove those values using the following command:
I read at somewhere in Stack Overflow that to empty your array you can do many things but a set is the fastest way to do this. Please let me know if you know any other way which is better than this.
final
.findOneAndUpdate({email:"abcd#gmail.com"}, {$set:{stocks:[]}})
.then(()=>console.log("Data removed."))
.catch(err=>console.log(err));
Once data is removed it means the array will get emptied. Then I assign the whole set of the new array from my local variable like this:
const newData = {
stocks : ["abcd", "wxyz"]
};
Now I am trying to assign this new array to my database using this command:
final
.findOneAndUpdate({email:"abcd#gmail.com"}, {$set:{stocks:newData.stocks}});
It is emptying the array successfully, but when I am assigning new array it is not working and shows an empty array. Can anyone assist me with this, please?
Try with
final.findOneAndUpdate({email:"abcd#gmail.com"}, {$set:{stocks:newData.stocks}}, {new: true})
.then((doc)=>console.log(doc))
.catch(err=>console.log(err));
If you don't use a callback the query is not executed.
The query executes if callback is passed else a Query object is returned.
Mongoose documentation

getting data from an object's array with vue.js

I am trying to access the following data in Vue.js
{"id":1,"name":"Westbrook","created_at":"2017-06-10T16:03:07.336Z","updated_at":"2017-06-10T16:03:07.336Z","stats":[{"id":1,"player_id":1,"points":2558,"assists":840,"rebounds":864,"created_at":"2017-06-10T16:03:07.373Z","updated_at":"2017-06-10T16:03:07.373Z"}]}
self.player = response.name works. now i need self.point
methods: {
fetchData: function() {
var self = this;
$.get("api/v1/players/1", function(response) {
console.log(response);
self.player = response.name;
self.point = response.stats.points
});
}
}
I have thus far tried response.stats["points"], response.stats[2], response.stats[ { points } ], response.stats[points]
The stats property in your json holds an array in which the first object has a property named points
So use response.stats[0].points
Keep in mind though that the stats is probably an array for a reason. It might hold more than one objects in the future, so always using the first element [0] might not be a valid approach.
I think it can help you
var json = JSON.parse(data);
json.stats[0].points
response = {"id":1,"name":"Westbrook","created_at":"2017-06-10T16:03:07.336Z","updated_at":"2017-06-10T16:03:07.336Z","stats":[{"id":1,"player_id":1,"points":2558,"assists":840,"rebounds":864,"created_at":"2017-06-10T16:03:07.373Z","updated_at":"2017-06-10T16:03:07.373Z"}]}
If you want to access the name
console.log(response.name) // Westbrook
If you want to access the stats data which contain list, simply target
let stats=response.stats[0] //By getting the first index in the list
Get the points in stats
console.log(stats.points) // 2588

array push of records obtained from mongo db

In MEAN stack, I am trying to store the records obtained from mongo db in an array, but I am not able to store the record in an array.
This is my code, I am trying to push the records obtained from projectimage to fulldetails[] array, but it failed. Suggest me the possible solution to store the mongo db records to array
var express = require("express"),
router = express.Router(),
project = require("../../models/project.js"),
projectimage = require("../../models/projectimages.js"),
var details=data;
var fulldetails=[];
for (var i = 0; i < details.length; i++) {
var prjct_id=details[i]._id;
console.log('below'+i);
fulldetails.push(details[i]);
projectimage.findOne({projectId: prjct_id}, function(err, data){
fulldetails.concat(data);
});
console.log(fulldetails);
return false;
}
I think what do you want is to get an array from your Mongo collection, correct me if I am wrong.
I am also assuming that Mongo query runs successfully, and returns the records correctly. then you can use toArray function to get array in callback.
// let's say Furniture is your collection
let furniture = Furniture.find({});
let details = [];
furniture.toArray((err, array) => {
if (err) return;
details = array; // now details has your collections' documents
});
For more refer this
Let me know if this is not what you were looking for.
I think you're trying to get a flat array of full details. If my assumption is correct, you could try my solution here:
var fulldetails=[];
for (var i = 0; i < details.length; i++) {
var prjct_id=details[i]._id;
projectimage.find({projectId: prjct_id}).toArray(function(err, data){ //convert data to array first
console.log(data);
fulldetails.concat(data); // concat data to fulldetails to get a flat array
});
}

Synchronized Array (for likes/followers) Best Practice [Firebase Swift]

I'm trying to create a basic following algorithm using Swift and Firebase. My current implementation is the following:
static func follow(user: FIRUser, userToFollow: FIRUser) {
database.child("users").child(user.uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
var dbFollowing: NSMutableArray! = snapshot.value!["Following"] as! NSMutableArray!
dbFollowing?.addObject(userToFollow.uid)
self.database.child("users/"+(user.uid)+"/").updateChildValues(["Following":dbFollowing!])
//add user uid to userToFollows followers array in similar way
}) { (error) in
print("follow - data could not be retrieved - EXCEPTION: " + error.localizedDescription)
}
}
This retrieves the array of from Firebase node Following, adds the uid of userToFollow, and posts the new array to node Following. This has a few problems:
It is not synchronized so if it is called at the same time on two devices one array will overwrite the other and followers will not be saved.
If there are no followers it cannot deal with a nil array, the program will crash (not the main concern, I can probably address with optionals).
I was wondering what the best practice might be to created a synchronized array of uid/tokens for user followers or post likes. I found the following links, but none seem to directly address my problem and seem to carry other problems with it. I figured it would be wise to ask the community with experience instead of Frankensteining a bunch of solutions together.
https://firebase.googleblog.com/2014/05/handling-synchronized-arrays-with-real.html
https://firebase.google.com/docs/database/ios/save-data (the save data as transaction section)
Thanks for your help!
Thanks to Frank, I figured out a solution using runTransactionBlock. Here it is:
static func follow(user: FIRUser, userToFollow: FIRUser) {
self.database.child("users/"+(user.uid)+"/Following").runTransactionBlock({ (currentData: FIRMutableData!) -> FIRTransactionResult in
var value = currentData?.value as? Array<String>
if (value == nil) {
value = [userToFollow.uid]
} else {
if !(value!.contains(userToFollow.uid)) {
value!.append(userToFollow.uid)
}
}
currentData.value = value!
return FIRTransactionResult.successWithValue(currentData)
}) { (error, committed, snapshot) in
if let error = error {
print("follow - update following transaction - EXCEPTION: " + error.localizedDescription)
}
}
}
This adds the uid of userToFollow to the array Following of user. It can handle nil values and will initialize accordingly, as well as will disregard the request if the user is already following the uid of userToFollow. Let me know if you have any questions!
Some useful links:
The comments of firebase runTransactionBlock
The answer to Upvote/Downvote system within Swift via Firebase
The second link I posted above

Resources