Retrieve only a particular number of child records - c#

If I write
db.Topics.Include("ChildTopics")
then it gives all the child comments for that. But what I want is only the top two child topics ordered by "childtopic created date".

This is not possible to include only the first two via Include method.
In your case, you can do this :
var firstTwo = from topic in datacontext.Topics
select new { Topic= topic, ChildTopic= topic.ChildTopics.OrderBy(c => c.childtopic_created_date).Take(2) };

Include does an early load of all dependencies, but I am not aware of a way to apply restrictions on this implementation.
An alternate way would be to shape the results like:
var comments = db.Topics.Select(_x=>
new{
Topic = _x,
TopTwoChildTopics = _x.ChildTopics.Top(2)
});

Related

Firebase search nested child's with value [duplicate]

Given the data structure below in firebase, i want to run a query to retrieve the blog 'efg'. I don't know the user id at this point.
{Users :
"1234567": {
name: 'Bob',
blogs: {
'abc':{..},
'zyx':{..}
}
},
"7654321": {
name: 'Frank',
blogs: {
'efg':{..},
'hij':{..}
}
}
}
The Firebase API only allows you to filter children one level deep (or with a known path) with its orderByChild and equalTo methods.
So without modifying/expanding your current data structure that just leaves the option to retrieve all data and filter it client-side:
var ref = firebase.database().ref('Users');
ref.once('value', function(snapshot) {
snapshot.forEach(function(userSnapshot) {
var blogs = userSnapshot.val().blogs;
var daBlog = blogs['efg'];
});
});
This is of course highly inefficient and won't scale when you have a non-trivial number of users/blogs.
So the common solution to that is to a so-called index to your tree that maps the key that you are looking for to the path where it resides:
{Blogs:
"abc": "1234567",
"zyx": "1234567",
"efg": "7654321",
"hij": "7654321"
}
Then you can quickly access the blog using:
var ref = firebase.database().ref();
ref.child('Blogs/efg').once('value', function(snapshot) {
var user = snapshot.val();
ref.child('Blogs/'+user+'/blogs').once('value', function(blogSnapshot) {
var daBlog = blogSnapshot.val();
});
});
You might also want to reconsider if you can restructure your data to better fit your use-case and Firebase's limitations. They have some good documentation on structuring your data, but the most important one for people new to NoSQL/hierarchical databases seems to be "avoid building nests".
Also see my answer on Firebase query if child of child contains a value for a good example. I'd also recommend reading about many-to-many relationships in Firebase, and this article on general NoSQL data modeling.
Given your current data structure you can retrieve the User that contains the blog post you are looking for.
const db = firebase.database()
const usersRef = db.ref('users')
const query = usersRef.orderByChild('blogs/efg').limitToLast(1)
query.once('value').then((ss) => {
console.log(ss.val()) //=> { '7654321': { blogs: {...}}}
})
You need to use limitToLast since Objects are sorted last when using orderByChild docs.
It's actually super easy - just use foreslash:
db.ref('Users').child("userid/name")
db.ref('Users').child("userid/blogs")
db.ref('Users').child("userid/blogs/abc")
No need of loops or anything more.

How to select nested attribute in scan in DynamoDB?

I realize this is answered in the documentation (basically, "use the dot syntax"), but I'm still missing something. I'm using the .NET SDK and need to be able to select just a few attributes from a scan, one of which is a boolean inside a Map attribute. Note that I'm not trying to filter the results. I want all of the items, but I only want some of the attributes returned to me.
var config = new ScanOperationConfig
{
AttributesToGet = new List<string> { "foo.bar" },
Select = SelectValues.SpecificAttributes
};
var search = Table.Scan(config);
var documents = await search.GetRemainingAsync();
This code gets me the items I expect, but it's missing the "foo.bar" attribute. I know I can select the entire foo object, but I'm trying to minimize the amount of data handed back. I don't want the other attributes inside the foo object.
The relevant attribute of the item has the following JSON format:
{
"foo": {
"bar": true
}
}
I checked spelling, case sensitivity, etc. to no avail. Any idea what's wrong?
Instead of using Table.Scan, use the AmazonDynamoDBClient and you get more options.
The Client's ScanAsync method takes a ScanRequest which has a ProjectionExpression string. This is not present on the ScanOperationConfig class and that was the source of confusion.
Use the ProjectionExpression like so:
var scanRequest = new ScanRequest(Table.TableName)
{
ProjectionExpression = "foo.bar"
};
According to the documentation on ProjectionExpression:
ProjectionExpression replaces the legacy AttributesToGet parameter.
I didn't realize AttributesToGet was legacy until finally looking at the client for a totally unrelated problem and happened to find my answer to this problem.

MVC4 ToList() show first few records

I'm just learning how to use .net and mvc4 and I have a problem. I have no idea how to show only the first 5(or any number) rows in a table. This is how I'm currently sending my information to the view.
public ActionResult ActiveCampaigns()
{
var campaigns = db.ActiveCampaigns.ToList();
return View(campaigns);
}
Thanks :)
Update:
Thanks for the quick responses! So simple!
db.ActiveCampaigns.Take(5).ToList()
I searched high and low and couldn't find this, my google-fu must be off. Thanks again!
The basic approach would be
var campaigns = db.ActiveCampaigns.Take(5).ToList();
But depending on what type of Context db is, this might fail. Skip() and Take() are not always available or allowed on all IEnumrable-derived interfaces. In that case read the error. Usually you can fix it in two ways:
var campaigns = db.ActiveCampaigns.ToList().Take(5); // expensive with many Campaigns
or, when you have a convenient sort-criterium:
var campaigns = db.ActiveCampaigns.OrderByDescending(c => c.Date).Take(5).ToList();
Enumerable.Take
public ActionResult ActiveCampaigns()
{
var campaigns = db.ActiveCampaigns.Take(5).ToList();
return View(campaigns);
}
I assume you're interested in paging, in which case, you'd need to use the Skip() method, also:
var campaigns = db.ActiveCampaigns.Skip(5).Take(5).ToList();
would get you page 2. Obviously, you're going to want to use a formula to handle which page to display:
var campaigns = db.ActiveCampaigns.Skip((page-1) * 5).Take(5).ToList();

MongoDB C# Driver multiple field query

Using the MongoDB C# driver How can I include more than one field in the query (Im using vb.net)
I know how to do (for name1=value1)
Dim qry = Query.EQ("name1","value1")
How can I modify this query so I can make it find all documents where name1=value1 and name2=value2?
( Similar to )
db.collection.find({"name1":"value1","name2":"value2"})
I wanted to search a text in different fields and Full Text Search doesn't work for me even after wasting so much time. so I tried this.
var filter = Builders<Book>.Filter.Or(
Builders<Book>.Filter.Where(p=>p.Title.ToLower().Contains(queryText.ToLower())),
Builders<Book>.Filter.Where(p => p.Publisher.ToLower().Contains(queryText.ToLower())),
Builders<Book>.Filter.Where(p => p.Description.ToLower().Contains(queryText.ToLower()))
);
List<Book> books = Collection.Find(filter).ToList();
You can use:
var arrayFilter = Builders<BsonDocument>.Filter.Eq("student_id", 10000)
& Builders<BsonDocument>.Filter.Eq("scores.type", "quiz");
Reference: https://www.mongodb.com/blog/post/quick-start-csharp-and-mongodb--update-operation
And doesn't always do what you want (as I found was the case when doing a not operation on top of an and). You can also create a new QueryDocument, as shown below. This is exactly the equivalent of what you were looking for.
Query.Not(new QueryDocument {
{ "Results.Instance", instance },
{ "Results.User", user.Email } }))

Parse XML using LINQ and fill existing object's properties rather than creating a new one

What I have now is the following code:
Tutorial tutorial =
(from tutorial in xmlDoc.Descendants("Tutorial")
select new Tutorial
{
Author = tutorial.Element("Author").Value,
Title = tutorial.Element("Title").Value,
Date = DateTime.Parse(tutorial.Element("Date").Value),
}).First();
myTutorial.Author = tutorial.Author;
myTutorial.Title = tutorial.Title;
myTutorial.Date = tutorial.Date;
myTutorial is passed from another method. And the code below has to 'fill' it.
The question is: Is there a way to create a LINQ query, which will assign values to the properties of an existing object, rather that creating a new one.
I would like my code to look something like this:
Tutorial tutorial =
(from tutorial in xmlDoc.Descendants("Tutorial")
select myTutorial
{
Author = tutorial.Element("Author").Value,
Title = tutorial.Element("Title").Value,
Date = DateTime.Parse(tutorial.Element("Date").Value),
});
The problem I have is:
I have an object which initially only has half of it's properties set, later I need to fill the rest of the properties. This needs to be done asynchronously.
My Approach:
I use WebClient's asynchronous method DownloadStringAsync to download XML file. In the event handler I wan't to fill an object with the properties it misses. And that's why I would like to directly pass values to my object rather than creating a new one.
Please let me know if it is not the best approach.
OK, this is pure evil:
var dropThis =
(from tutorial in xmlDoc.Descendants("Tutorial")
select new
{
Author = (myTutorial.Author = (string)tutorial.Element("Author")),
Title = (myTutorial.Title = (string)tutorial.Element("Title")),
Date = (myTutorial.Date = (DateTime)tutorial.Element("Date")),
}).First();
LINQ functional queries are actually designed in such way, that they shouldn't modify existing objects or collections, i.e. preserve state (although there are ways (hacks?) to do so).
But you can pretty easily implement reflection-based method to achieve what you want.
I noticed this question and felt the need to add another dirty solution. How about Extension methods?
public static void AddTo(this IEnumerable<Tutorial> source, Tutorial projection)
{
if (source.Count() == 0)
return;
projection.Title = source.First().Title;
projection.Author = source.First().Author;
projection.Date = source.First().Date;
}
Now you can just call it to add to your current tutorial. Also, I recommend using (string) instead of .Value so you avoid null reference exceptions.
tutorialXml
.Descendants("Tutorial")
.Select(tutorial => new Tutorial
{
Author = (string) tutorial.Element("Author"),
Title = (string) tutorial.Element("Title"),
Date = DateTime.Parse((string) tutorial.Element("Date")),
})
.AddTo(myTutorial);
Anyway, Good luck. Just wanted to add a dirty solution to this ball of mud.

Categories

Resources