Running a forEach loop in Mongoose, in reverse - express

I'm currently trying to make a faux blog style page. All the relevant information is in MongoDB and I'm extracting it using a forEach loop.
`<% blogs.forEach(function(blog){ %>
<img src="<%= blog.image %>" >
<%=blog.title%>
<span><%= blog.created.toDateString() %></span>
<p><%- blog.body.substring(0, 100) %>...</p>
<% }) %>`
The database contains these objects when you create/edit a post. When you run a forEach it will start at the beginning of the database and then work forwards. I'm trying to figure out how to make it go in reverse as a typical blog site will push older posts down the page when new content is posted (as of now it's displaying the first post first, second one second, etc.)
I thought about creating a for loop and constraining the length of it by using the .count() mongoose command but I can't seem to figure out how I can relate it the various objects in the database. Basically I'm trying to convert this forEach to use a variable (like [i]).

Use the Mongoose . It is a MongoDB object modeling tool designed to work in an asynchronous environment. Mongoose makes it very easy to work with MongoDB. You can try these (some of these may not work properly) , hopefully it will help you.
model_name.find({}).sort('-date').exec(function(err, docs) { ... });
model_name.find({}).sort({date: -1}).exec(function(err, docs) { ... });
model_name.find({}).sort({date: 'desc'}).exec(function(err, docs) { ... });
model_name.find({}).sort({date: 'descending'}).exec(function(err, docs) { ... });
model_name.find({}).sort([['date', -1]]).exec(function(err, docs) { ... });
model_name.find({}, null, {sort: '-date'}, function(err, docs) { ... });
model_name.find({}, null, {sort: {date: -1}}, function(err, docs) { ... });

Related

Is it okay to update or delete data inside of router.post, instead of .delete/.patch?

I created some example code underneath to show what I mean.
Is it okay to update some data after saving inside of a post route? I often update and save data in a single route, and I never know if it is okay to do this and if there are any consequences of the code that I am unaware of.
router.post('/sync-steam', auth, async(req, res) => {
const { steamID, steamName } = req.body
try {
await req.user.save( steamID )
await req.user.updateOne( steamName )
res.send("OK")
} catch(err) {
res.status(400).send(err)
}
})
Yes, it is OK to do that. There should not be any issues regarding that as long as your logic that communicates with your database is correct.
However, you should try to follow the convention of REST API, and use the correct method:
GET for listing/reading content
POST for creating content
PUT for replacing content
PATCH for updating part of the content
DELETE for deleting content

Is there a way to bind a variable number of queries?

I'm coding an app for managing shift work. The idea is pretty simple: the team is shared between groups. In those groups are specific shifts. I want to get something like that:
Group 1
- shift11
- shift12
- shift13
Group 2
- shift21
- shift22
- shift23
I already made a couple of tests, but nothing is really working as I would like it to: everything reactive, and dynamic.
I'm using vue.js, firestore (and vuefire between them).
I created a collection "shiftGroup" with documents (with auto IDs) having fields "name" and "order" (to rearrange the display order) and another collection "shift" with documents (still auto IDs) having fields "name", "order" (again to rearrange the display order, inside the group) and "group" (the ID of the corresponding shiftGroup.)
I had also tried with firestore.References of shifts in groups, that's when I was the closest to my goal, but then I was stuck when trying to sort shifts inside groups.
Anyway, with vuefire, I can easily bind shiftGroup like this:
{
data () {
return {
shiftGroup: [], // to initialize
}
},
firestore () {
return {
shiftGroup: db.collection('shiftGroup').orderBy('order'),
}
},
}
Then display the groups like this:
<ul>
<li v-for="(group, idx) in shiftGroup" :key="idx">{{group.name}}</li>
</ul>
So now time to add the shifts...
I thought I could get a reactive array of shifts for each of the groups, like that:
{
db.collection('shift').where('group', '==', group.id).orderBy('order').onSnapshot((querySnapshot) => {
this.shiftCollections[group.id] = [];
querySnapshot.forEach((doc) => {
this.shiftCollections[group.id].push(doc.data());
});
});
}
then I'd call the proper list like this:
<ul>
<li v-for="(group, idx) in shiftGroup" :key="idx">
{{group.name}}
<ul>
<li v-for="(shift, idx2) in shiftCollections[group.id]" :key="idx1+idx2">{{shift.name}}</li>
</ul>
</li>
</ul>
This is very bad code, and actually, the more I think about it, the more I think that it's just impossible to achieve.
Of course I thought of using programmatic binding like explained in the official doc:
this.$bind('documents', documents.where('creator', '==', this.id)).then(
But the first argument has to be a string whereas I need to work with dynamic data.
If anyone could suggest me a way to obtain what I described.
Thank you all very much
So I realize this is an old question, but it was in important use case for an app I am working on as well. That is, I would like to have an object with an arbitrary number of keys, each of which is bound to a Firestore document.
The solution I came up with is based off looking at the walkGet code in shared.ts. Basically, you use . notation when calling $bind. Each dot will reference a nested property. For example, binding to docs.123 will bind to docs['123']. So something along the lines of the following should work
export default {
name: "component",
data: function () {
return {
docs: {},
indices: [],
}
},
watch: {
indices: function (value) {
value.forEach(idx => this.$bind(`docs.${idx}`, db.doc(idx)))
}
}
}
In this example, the docs object has keys bound to Firestore documents and the reactivity works.
One issue that I'm trying to work through is whether you can also watch indices to get updates if any of the documents changes. Right now, I've observed that changes to the Firestore documents won't trigger a call to any watchers of indices. I presume this is related to Vue's reactivity, but I'm not sure.

Laravel Queries / Controller Edits

So I am pretty new to Laravel, and I have spent the whole day fishing through various documentations but I am stuck on the way queries work within the actual application. Right now, I am trying to get some data in my database to display, and I looked at the query builder so that's where I am right now. I am also using a CRUD based admin panel for entry in the database. And since it is CRUD based, it has created the model and the controller already, so I am wondering if I need to edit any of those files to get this to work. Here is what the public function index() has right now (Using Laraadmin):
$module = Module::get('Events');
if(Module::hasAccess($module->id)) {
return View('la.events.index', [
'show_actions' => $this->show_action,
'listing_cols' => $this->listing_cols,
'module' => $module
]);
} else {
return redirect(config('laraadmin.adminRoute')."/");
}`
Obviously, I am trying to display some data from this Events table into my blade view. From what I was reading, I understood (or I thought) that it would be something similar to this:
foreach ($module as $module) {
echo $module->id;
}
But, I keep getting an error that whatever variable I pass in the loop is undefined, although I thought it was in the controller. Right now my model is just returning the view as well. Any help with this is greatly appreciated, or even just an explanation of the relationships with queries in Laravel. Thanks!
A few things to check when this happens:
Change module to a known array. This tests if your data array is set up correctly:
'module' => [ '1', '2', '3' ], // previously $module
Within the blade, now write a simple loop, such as:
#foreach ($module as $m)
{{ $m }}
#endforeach
If this version does work, then you know you have something up with your $module variable.
If the above still doesn't work, try to simplify your view request (temporarily):
view('foo', ['a' => 555]);
Then in foo.blade.php, simply have:
hello {{ a }}
EDIT
If all this seems to be correct, then the data being fetched is probably wrong (so its not a view issue). Try $module = Module::all();
It seems like you are returning a view that doesn't exist. If what you have now was correct, it would be looking for resources/views/la/events/index.blade.php Try replacing that return view line with this:
return view('events', [ ... rest of your variables ]);
And just a side note, on your foreach statement, it's probably best to use two separate variable names... so something like:
foreach ($module as $element) { ...

How to use store.filter / store.find with Ember-Data to implement infinite scrolling?

This was originally posted on discuss.emberjs.com. See:
http://discuss.emberjs.com/t/what-is-the-proper-use-of-store-filter-store-find-for-infinite-scrolling/3798/2
but that site seems to get worse and worse as far as quality of content these days so I'm hoping StackOverflow can rescue me.
Intent: Build a page in ember with ember-data implementing infinite scrolling.
Background Knowledge: Based on the emberjs.com api docs on ember-data, specifically the store.filter and store.find methods ( see: http://emberjs.com/api/data/classes/DS.Store.html#method_filter ) I should be able to set the model hook of a route to the promise of a store filter operation. The response of the promise should be a filtered record array which is a an array of items from the store filtered by a filter function which is suppose to be constantly updated whenever new items are pushed into the store. By combining this with the store.find method which will push items into the store, the filteredRecordArray should automatically update with the new items thus updating the model and resulting in new items showing on the page.
For instance, assume we have a Questions Route, Controller and a model of type Question.
App.QuestionsRoute = Ember.Route.extend({
model: function (urlParams) {
return this.get('store').filter('question', function (q) {
return true;
});
}
});
Then we have a controller with some method that will call store.find, this could be triggered by some event/action whether it be detecting scroll events or the user explicitly clicking to load more, regardless this method would be called to load more questions.
Example:
App.QuestionsController = Ember.ArrayController.extend({
...
loadMore: function (offset) {
return this.get('store').find('question', { skip: currentOffset});
}
...
});
And the template to render the items:
...
{{#each question in controller}}
{{question.title}}
{{/each}}
...
Notice, that with this method we do NOT have to add a function to the store.find promise which explicitly calls this.get('model').pushObjects(questions); In fact, trying to do that once you have already returned a filter record array to the model does not work. Either we manage the content of the model manually, or we let ember-data do the work and I would very much like to let Ember-data do the work.
This is is a very clean API; however, it does not seem to work they way I've written it. Based on the documentation I cannot see anything wrong.
Using the Ember-Inspector tool from chrome I can see that the new questions from the second find call are loaded into the store under the 'question' type but the page does not refresh until I change routes and come back. It seems like the is simply a problem with observers, which made me think that this would be a bug in Ember-Data, but I didn't want to jump to conclusions like that until I asked to see if I'm using Ember-Data as intended.
If someone doesn't know exactly what is wrong but knows how to use store.push/pushMany to recreate this scenario in a jsbin that would also help too. I'm just not familiar with how to use the lower level methods on the store.
Help is much appreciated.
I just made this pattern work for myself, but in the "traditional" way, i.e. without using store.filter().
I managed the "loadMore" part in the router itself :
actions: {
loadMore: function () {
var model = this.controller.get('model'), route = this;
if (!this.get('loading')) {
this.set('loading', true);
this.store.find('question', {offset: model.get('length')}).then(function (records) {
model.addObjects(records);
route.set('loading', false);
});
}
}
}
Since you already tried the traditional way (from what I see in your post on discuss), it seems that the key part is to use addObjects() instead of pushObjects() as you did.
For the records, here is the relevant part of my view to trigger the loadMore action:
didInsertElement: function() {
var controller = this.get('controller');
$(window).on('scroll', function() {
if ($(window).scrollTop() > $(document).height() - ($(window).height()*2)) {
controller.send('loadMore');
}
});
},
willDestroyElement: function() {
$(window).off('scroll');
}
I am now looking to move the loading property to the controller so that I get a nice loader for the user.

How to get all artists of a user (Spotify Api 1.x)?

I'm trying to get a list of Artists for a user. It was very easy in the 0.x Api, but now i can't do it.
require([
'$api/models',
'$api/location#Location',
'$api/library#Library',
'$api/search#Search',
'$api/toplists#Toplist',
'$views/buttons',
'$views/list#List',
'$views/image#Image'
], function(models, Location, Library, Search, Toplist, buttons, List, Image) {
var librarys = Library.forCurrentUser();
console.log("LIBRARY", librarys);
librarys.load("artists").done(
function(artists) {
console.log(artists);
artists.load('owner').done(function(snapshot) {
console.log("SNAP",snapshot);
});
});
});
I get a response of "Library.forCurrentUser();" but everything i try next fails. There is no error or something, but either "librarys.load("artists")" nor "librarys.snapshot()" works.
By loading "artists" from the library, you're actually not getting artists back in the callback function, but a library that has loaded the artists. Since you almost never need to have everything loaded, it's better for performance if you specify what you want to have loaded. If you wanted to load tracks as well as artists, simply use "artists", "tracks" as load parameter.
If you want to see the Artists in the current user's library, you can do like so:
require(['$api/library#Library'], function(Library) {
Library.forCurrentUser().load("artists").done(function(library) {
library.artists.snapshot().done(function(snapshot) {
for (var i = 0; i < snapshot.length; i++) {
console.log(snapshot.get(i).name);
}
});
});
});
Hope this helps.
Edit: This is working for the Spotify Apps API version 1.25.1.