Query result with nested vertices - orientdb

[OrientDB beginner here..]
I have a data structure like the following:
User <[PostEdge]- Post <[CommentEdge]- Post
^[CommentEdge]- Post
^[CommentEdge]- Post
So, a post is related to a user via PostEdge, and another post may be related to a post via CommentEdge.
I'm trying to query for a data structure that gives me something like the following:
[
{
content: "",
comments: [{content: ""}, {content: ""}, {content: ""}],
poster: {name: ""}
}
]
The closest I've gotten so far is..
SELECT uuid, content, created_on, IN('CommentEdge') as comments, in('PostEdge') as poster
FROM (SELECT expand(out('PostEdge')) FROM #28:0)
WHERE outE('CommentEdge').size() = 0
This returns me something like..
[
{content: "", comments: [#12:0, #13:0, #14:0], poster: [#15:0]}
]
I've spent a good day trying to figure this out and I'm coming up short. That, and I'm fairly certain that the 'FROM (SELECT.....` part isn't a good idea. So, first, is there a function or something that I'm missing that includes those records rather than just gives back the record ID? Second, is there a better way of doing what I'm trying to do? (Which I assume there is, I'm just not there yet in know-how).

So, what I was looking for was a 'fetchplan'. This ended up solving my issue.
https://orientdb.com/docs/2.2/Fetching-Strategies.html
Essentially, fetchplan is an instruction that tells the query to expand/traverse linked documents.
My close-to-end result is like..
SELECT content, uuid, created_on, #rid, in('CommentEdge') as comments
FROM (SELECT expand(out('PostEdge')) FROM :userId WHERE outE('CommentEdge').size() = 0 )
FETCHPLAN comments:1

Related

Meteor: find by full name (multiple fields)

I'm implementing persons list inside my Meteor app. Every person has a lastName and firstName. I want to be able to search by full name or it's part. Of course search must be case insensitive. There will be about 500 persons, so I need pagination & I can't just filter the results on client side.
My general idea is to generate additional field fullName upon insert or update of a person:
fullName: lastName.toLowerCase() + ' ' + firstName.toLowerCase(),
And then just use it inside the find method:
PersonsCollection.find({ fullName: {$regex : searchString}, ... })
I'm pretty new to Meteor, Mongo and backend in general. I spent some time researching, but still confused. My questions are:
Is there any real reasons against my implementation besides it's kinda ugly to create additional field?
Is there a conventional way to do this in Meteor?
It is usual to create an additional field.
But you can try to use an $or:
PersonsCollection.find(
{
$or: [
{ firstName: new RegExp(searchString, 'i') },
{ lastName: new RegExp(searchString, 'i') }
]
}
);
Don't forgot to create indexes to your search fields.

Mongoose Model.deleteMany() only deletes first element of matches

I'm trying to use the Model.deleteMany() function from mongoose. I'm trying to do something like this:
MyModel.deleteMany({"_id": {$in: ['objectid 1', 'objectid 2'
But this only deletes the first element of the matches from DB (in this case, if 'objectid 1' exists in the DB, it deletes that, but if it isn't nothing happens (both n and deletedCount is 0 in the returned data from the function). I tried using something other than the _id as a query, and this worked. If I had three elements with the same 'name' field, I could delete these.
I tried _id both with and without quotation marks. I also tried converting the object id strings to actual object ids before passing them to deleteMany, but this had no difference either. I have also of course tried to google this, but everything I've found are examples of usage, where it looks like I'm doing the exact same thing as the various blog posts.
I haven't added much code here because I don't really see what else I could be adding. I'm already printing out the input to the $in object, and this is correct. The strangest thing, I think, is that the first element of the list is deleted. Is it treated as a deleteOne request for some reason? are there any config options I need?
As per request, I've added the query and the documents I'd hope to delete:
//Request
MemberModel.deleteMany({"_id": {$in: [
5ee4f6308631dc413c7f04b4,
5ee4f6308631dc413c7f04b5,
5ee4f6308631dc413c7f04b6
]}};
//Expected to be deleted
[
{
"_id": "5ee4f62f8631dc413c7f04b5",
"firstName": "Name",
"lastName": "Nameson",
"__v": 0
},
{
"_id": "5ee4f62f8631dc413c7f04b6",
"firstName": "Other",
"lastName": "Person",
"__v": 0
}
]
If you have any ideas for what I could try, that would be much appreciated.

MongoDB agregation: get next and previous element [duplicate]

I have a blog. On the individual post page I want to display a link to the previous, and if there is one, next post published in the bottom. The link should be the title of the specific post.
How do I do that the simplest way with Mongoose?
My current controller looks like this:
Post.findOne { slug : req.params.slug }, (err, post) ->
res.render "blog/show.jade", locals: title: "This post", post: post
And the schema looks like this:
PostSchema = new Schema(
title:
type: String
required: true
index: true
preamble: String
body: String
slug: String
createdAt: Date
updatedAt: Date
)
So let suppose you have schema like this:
{
_id,
text
}
I suppose that _id is mongo ObjectId, so we it contains post date and i can sort on it
Lets consider that i have opened current post with id equal to ObjectId( "43cc63093475061e3d95369d") (instead of this i will use curId) and i need to know next one and previous. Also lets consider that we need get all posts one by one ordered by created date descending:
Get next post you can like this:
db.posts.find({_id: {$gt: curId}}).sort({_id: 1 }).limit(1)
Get previous post you can like this:
db.posts.find({_id: {$lt: curId}}).sort({_id: -1 }).limit(1)
Few things:
If you don't use mongodb ObjectId above code will not work for you, but you can still use postDate instead of id and current post postDate instead of curId.
Take care about order when getting next/prev posts, to retrieve next post you need sort asc, to retrieve prev post you need sort desc.
I am not familiar with mongoose, so above scripts is mongodb shell scripts.
Find previous item:
Post.findOne({_id: {$lt: curId}}).sort({_id: -1}).exec(cb)
Find next item:
Post.findOne({_id: {$gt: curId}}).sort({_id: 1}).exec(cb)

How to find and return a specific field from a Mongo collection?

Although I think it is a general question, I could not find a solution that matches my needs.
I have 2 Mongo collections. The 'users' collection and the second one 'dbInfos'.
Now, I have a template called 'Infos' and want the already existing fields in the Mongo collections to be presented to the user in input fields in case there is data in the collection. When no data is provided in the database yet, it should be empty.
So here is my code, which works fine until I want to capture the fields from the second collection.
Template.Infos.onRendered(function() {
$('#txtName').val(Meteor.user().profile.name);
$('#txtEmail').val(Meteor.user().emails[0].address);
});
These 2 work great.
But I don´t know how to query the infos from the collection 'dbInfos', which is not the 'users' collection. Obviously Meteor.user().country does not work, because it is not in the 'users' collection. Maybe a find({}) query? However, I don´t know how to write it.
$('#txtCountry').val( ***query function***);
Regarding the structure of 'dbInfos': Every object has an _id which is equal to the userId plus more fields like country, city etc...
{
"_id": "12345",
"country": "countryX",
"city": "cityY"
}
Additionally, how can I guarantee that nothing is presented, when the field in the collection is empty? Or is this automatic, because it will just return an empty field?
Edit
I now tried this:
dbInfos.find({},{'country': 1, '_id': 0})
I think this is the correct syntax to retrieve the country field and suppress the output of the _id field. But I only get [object Object] as a return.
you're missing the idea of a foreign key. each item in a collection needs a unique key, assigned by mongo (usually). so the key of your country info being the same as the userId is not correct, but you're close. instead, you can reference the userId like this:
{
"_id": "abc123",
"userId": "12345",
"country": "countryX",
"city": "cityY"
}
here, "abc123" is unique to that collection and assigned by mongo, and "12345" is the _id of some record in Meteor.users.
so you can find it like this (this would be on the client, and you would have already subscribed to DBInfos collection):
let userId = Meteor.userId();
let matchingInfos = DBInfos.find({userId: userId});
the first userId is the name of the field in the collection, the second is the local variable that came from the logged in user.
update:
ok, i think i see where you're getting tripped it. there's a difference between find() and findOne().
find() returns a cursor, and that might be where you're getting your [object object]. findOne() returns an actual object.
for both, the first argument is a filter, and the second argument is an options field. e.g.
let cursor = DBInfos.find({
userId: Meteor.userId()
},
{
fields: {
country: 1
}
});
this is going to:
find all records that belong to the logged in user
make only the country and _id fields available
make that data available in the form of a cursor
the cursor allows you to iterate over the results, but it is not a JSON object of your results. a cursor is handy if you want to use "{{#each}}" in the HTML, for example.
if you simply change the find() to a findOne():
let result = DBInfos.findOne({ /** and the rest **/
... now you actually have a JSON result object.
you can also do a combination of find/fetch, which works like a findOne():
let result = DBInfos.find({
userId: Meteor.userId()
},
{
fields: {
country: 1
}
}).fetch();
with that result, you can now get country:
let country = result.country;
btw, you don't need to use the options to get country. i've been assuming all this code is on the client (might be a bad assumption). so this will work to get the country as well:
let result = DBInfos.findOne({userId: Meteor.userId()});
let country = result.country;
what's going on here? it's just like above, but the result JSON might have more fields in it than just country and _id. (it depends on what was published).
i'll typically use the options field when doing a find() on the server, to limit what's being published to the client. on the client, if you just need to grab the country field, you don't really need to specify the options in that way.
in that options, you can also do things like sort the results. that can be handy on the client when you're going to iterate on a cursor and you want the results displayed in a certain order.
does all that make sense? is that what was tripping you up?

Adding to a non-existent array in a collection with $addToSet

This should be very simple. I have two collections, one of which holds two types of data (name, age), and the other should simply add the age values to an array (with no duplicates).
I "start" my collections like usual:
People = new Mongo.Collection('people')
Ages = new Mongo.Collection('ages')
Right now I'm working with seed data, but the question could easily extend to when I actually want to dynamically add data to the array. I seed it like so:
Meteor.startup(function() {
if (People.find().count() === 0) {
[
{
name: 'John',
age: '24' //Yes, I want to store it as strings.
},
{ ... } //more data
]
.forEach(function(person) {
People.insert(person)
Ages.update({ $addToSet: {age: person.age}}) //Not working
})
}
})
That last part there is what's not working. I guess I figured $addToSet would fix things for me, since the docs say:
If the field is absent in the document to update, $addToSet creates
the array field with the specified value as its element.
Now I suppose I have to create the field first, but I'm not sure where or how. I have a strong, strong feeling that I'm overlooking something ridiculously simple here...
If I got it right, your db should look like that when filled
Persons (_id, name, age)
1, John, 24
2, Pete, 21
3, Michele, 27
4, Sandy, 21
Ages (_id, ageset)
?, [ 24, 21, 27 ]
Solution1: Just insert one record on a fix key and then only update this one.
Have a look at this MeteorPad
Solution2: Using a local Meteor.Collection which is synced by server an gets DISTINCT field values from package mrt:mongodb-aggregation.
Have a look at this MeteorPad
Solution3: Using a server side synced Mongo.Collection to hold the distinct ages list.
Have a look at this MeteorPad
Remark: Checkout log infos on server process. There are timeouts to add, change and remove a record for test and updates (5 sec, 10 sec, 15 sec)
Now right now, I see that you're defining your People collection, but I don't see you actually defining "person" or "Age" anywhere. Maybe thats just due to how you've formatted your answer.
Either way though, I'm not entirely sure you'd be getting anything to happen. As far as I know, you'll need to select the documents each time through the loop, as you want to update them.
This is how I'm doing something similar in an app I'm working on:
Meteor.users.update({ _id: Meteor.userId() }, { $addToSet: { 'profile.viewedRequests' : this._id }});
The key there being that I'm selecting an individual document, before attempting to update it.
Its either that, or you need to switch to People.update.