Removing an element from an array in MongoDB - c#

I am new to learning how to use MongoDB and am stuck pretty early on, so hoping someone can help me out with a simple example.
I can successfully connect to a Mongo server and create a collection and create objects to put in it. I am doing all of this through c# and the c# driver.
I have the following custom objects defined in my code.
public class Feature
{
public string FeatureName { get; set; }
public ObjectId Id { get; set; }
public List<Scenario> Scenarios { get; set; }
}
public class Scenario
{
private string _notes;
public string ScenarioName { get; set; }
public List<string> Givens { get; set; }
public List<string> Whens { get; set; }
public List<string> Thens { get; set; }
public string Explanation { get; set; }
public string Notes { get; set; }
}
As you can see, the Feature object contains a property which is a list of scenarios.
In my Mongo collection I have a Feature object that contains 3 scenarios. What I want to do in C# is write a method that can remove a specific scenario from a feature:
User provides a feature and scenario name to a method
Method checks the feature, looking through the list within it, for a scenario where the scenario.scenarioname matches the scenario name passed in to the method
If it exists, then remove the scenario from the feature and update Mongo and return a bool of true. If it doesn't exist return false
I am sure that this is probably going to be obvious when I see an example, but I have tried and get stuck trying to work through the List property looking for a property on a sub object.
I hope that all makes sense??!?
Thanks in advance.
P

Resolved it myself...
public bool DeleteScenario(string featureName, string scenarioName)
{
var collection = GetCollection<Feature>();
var query = Query.EQ("FeatureName", featureName);
var resultingFeature = collection.Find(query).SetLimit(1).FirstOrDefault();
if (resultingFeature == null)
{
return false;
}
// we have found our feature and it exists.
foreach (var scenario in resultingFeature.Scenarios)
{
if (scenario.ScenarioName == scenarioName)
{
resultingFeature.Scenarios.Remove(scenario);
collection.Save(resultingFeature);
return true;
}
}
return true;
}

Related

Access the field of an object in a Linked List - C#

I want to find all the objects in a Linked List which satisfy a certain requirement. Their internal state (one field) must assume a specific value.
Consider these three classes (I will give only essential information):
public class Notification
{
public DateTime timeStamp { get; private set; }
public uint sourceApp { get; private set; }
public int [,,] icon { get; private set; }
}
public class PearStack
{
public LinkedList<Notification> notifications { get; private set; }
//...
}
public class NotificationDispatcher
{
public PearStack[] pearStacks { get; private set; }
public NotificationDispatcher(uint s, PearStack pearstack)
{
//...
}
//...
}
In the constructor "NotificationDispatcher" I have as input a "PearStack" object and an integer.
A PearStack object (pearstack) has a linked list of Notifications.
I want to select all the objects (Notifications) of the linked list contained in pearstack which have the field "sourceapp" equal to "s".
I thought about:
pearstack.notifications.Find(s)
But it is wrong.
Can anyone help me please?
I'm pretty sure you can do this with a simple LINQ query:
var notificationsForApp = pearstack.notifications.Where(x => x.sourceApp == s);
This will give you an IEnumerable<Notification> where enumerating will only give you the notifications matching the source app. To enumerate immediately and get a List<Notification> or Notification[], simply append ToList() or ToArray() to the end of the statement.

C# Filter List of objects by string

I have a list of objects. Each object has n properties. I have a another list with m [1..n] property names.
Two questions:
How do I filter the list of objects by checking if one of the properties in the other list contains a string?
How do I filter the list of objects by checking if ANY property contains a string?
Here is the object class:
public class MyModel
{
public string POne { get; set; }
public string PTwo { get; set; }
public string PThree { get; set; }
}
In pseudocode in would be something like:
New List filtered
Foreach object o in myObjectList
If o.POne, o.PTwo or o.PThree contains string "test"
filtered.Add(o)
Else
Next
I tried to adapt the code from this post, but could not get a working.
Another thought would be to create a nested list with all property values. In that scenario I get the filtering working with the following line:
List<List<string>> filtered = testList.Where(q => q.Any(a => a.Contains(testString))).ToList();
But isn't that creating a lot of overhead by creating all those extra lists?
Performance is a concern for me.
Make your Class responsible for determing if it matches or not via a method
public class MyModel
{
public string POne { get; set; }
public string PTwo { get; set; }
public string PThree { get; set; }
public bool DoesMatch(string tomatch)
{
return POne.Equals(tomatch) ||
PTwo.Equals(tomatch) ||
PThree.Equals(tomatch);
}
}
Then you can do this
var filtered = testList.Where(q => q.DoesMatch("string to check"));

JSON (deserialized) sends null values to list

Firstly thank you for taking the time to look at this. It's quite alot.
Question:
I'm basically trying to download a json as a string and then deserialize it to a list. The reason why is so i can then call a specific property of that list (in my case 'ips' because it's all i actually need) and insert it into a table if requirements are met.
The problem is that it moves all null values into the array. 114 columns of null, or empty array and i can't figure out why?
I think i'll attach a link to the JSON because its a massive file its here https://endpoints.office.com/endpoints/Worldwide?clientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7
Here is my code:
Getters and setters for JSON
public class GetSetJsonIP {
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("serviceArea")]
public string ServiceArea { get; set; }
[JsonProperty("serviceAreaDisplayName")]
public string ServiceAreaDisplayName { get; set; }
[JsonProperty("urls")]
public IList<string> urls { get; set; }
[JsonProperty("ips")]
public IList<string> ips { get; set; }
[JsonProperty("tcpPorts")]
public string tcpPorts { get; set; }
[JsonProperty("expressRoute")]
public bool expressRoute { get; set; }
[JsonProperty("category")]
public string category { get; set; }
[JsonProperty("required")]
public bool required { get; set; }
[JsonProperty("notes")]
public string notes { get; set; }
[JsonProperty("udpPorts")]
public string udpPorts { get; set; }
}
List class
public class ConvertJsonIP{
public List<GetSetJsonIP> jsonIpConvert { get; set; }
public List<GetSetJsonIP> jsonIPConvert = new List<GetSetJsonIP>();
}
3.I download the JSON using an empty string called o365IP
o365IP = wc.DownloadString(wc.BaseAddress + "/endpoints/Worldwide?clientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7");
I deserialize using my List to a seperate var
var o365IpVerion = JsonConvert.DeserializeObject<List<ConvertJsonIP>>(o365IP);
This code shows no errors. so i can only assume its a logical one on my part. It should be noted that i had to put the <List< in to stop an error stating that it couldnt convert an object to an array.
Seriously, i've been stuck on this for 3 days so any help on this would be greatly appreciated! Thanks in advance!
the json you have is a list of objects and each of these objects conform to GetSetJsonIp. You should deserialize using List<GetSetJsonIP>
var o365IpVerion = JsonConvert.DeserializeObject<List<GetSetJsonIP>>(o365IP);
public class GetJsonIP works fine.
The reason you must Deserialize into a List<> is because the json object starts with a bracket making the entire object a List or array.
var O365IpVersion = JsonConvert.DeserializeObject<List<GetJsonIP>(O365IP);
There are different ways to fetch the value of a certain property. If you just need ips and want to check the value then update it, then you could loop:
JArray arr = JArray.Parse(O365IP);
foreach (JObject obj in arr.Children<JObject>())
{
foreach (JPRoperty prop in obj.Properties().Where(x => x.Name == "ips"))
{
//use prop.Value and perform tasks
}
}
Or just simply loop like this:
for (int i = 0; i < O365IpVersion.Count; i++)
{
//use O365IpVersion.ElementAt(i).ips

C# single list from different classes

I have 2 parts on an API that share some similarities but function differently. I am currently trying to take data from a list object of People from class B and add this data to a list of People created from Class A(hopefully explained well enough?)
The People structure in the 2 classes are actually the same:
[XmlRoot(ElementName = "people")]
public class People
{
[XmlElement(ElementName = "member")]
public List<Member> Member { get; set; }
}
[XmlRoot(ElementName = "member")]
public class Member
{
[XmlElement(ElementName = "firstName")]
public string FirstName { get; set; }
[XmlElement(ElementName = "lastName")]
public string LastName { get; set; }
[XmlAttribute(AttributeName = "memberId")]
public string MemberId { get; set; }
[XmlAttribute(AttributeName = "memberNotes")]
public string Notes { get; set; }
[XmlElement(ElementName = "departed")]
public string Departed { get; set; }
[XmlElement(ElementName = "currentPosition")]
public Name CurrentPosition { get; set; }
}
In normal operation the following code sets the People list just fine:
public People PersonData { get; set; }
...
....
var results = ApiA.People;
PersonData = results.Member; //during normal operation only one entry of member is returned
However in another operation the results returns a Larger list of member objects so I am trying to add to the same list to ensure handling later on uses single method for both operations due to the same data structure, what I am trying is as follows:
if(PersonData == null)
PersonData = new API_A.People();
var results = ApiB.People; //person data here belongs to API_B.Person
foreach (var res in results)
{
if (res?.Member != null)
{
if (PersonData == null)
{
PersonData.Member.AddRange(res.People.Member.Cast<API_A.Member>());
break;
}
else
PersonData.Member.Union(res.People.Member.Cast<API_A.Member>());
}
}
No errors are returned in the ide but during operation I continually receive a NullReferenceException during the add range operation; so as I am still learning I would really appreciate understanding what I am doing wrong here?
2 problems are obvious.
If PersonData is null, you cannot access to PersonData.Member before creating the PersonData object first. So in your case it should be:
PersonData = new People();
Next problem you'll have is the casting. Even if everything is same in 2 different classes, unless there is an inheritance relation between those, you cannot cast one to another. What you should do is to map your one class to the other. Just create a mapper method somewhere else that maps your API_A.Member to API_B.Member and/or vica versa. This kind of mapping workarounds are widely used, feel safe creating this heavy looking mapping method.
Example:
API_A.Member MapBToA(API_B.Member member)
{
return new API_A.Member {
CharacterName = member.CharacterName,
...
};
}

Removing properties of an object in List<>

I'm listening to "push" notifications coming into my server. I've set up SubscriptionModel with all possible properties, and I can correctly iterate through the JSON body coming through, parse each Subscription, and modify the output before returning the list I created. However, I'd like to know how I might go about removing properties of SubscriptionModel when I don't need to return them at all; or removing them if they're null before responding back with List<SubscriptionModel> subscriptions.
namespace TextMessagingListener.Controllers
{
public class SubscriptionModel
{
public long push_id { get; set; }
public string request_id { get; set; }
public string subscription_id { get; set; }
public string message { get; set; }
public string status_code { get; set; }
public string error_message { get; set; }
}
[Route("api/[controller]")]
public class SubscriptionController : Controller
{
// PUT api/subscription
[HttpPut]
public List<SubscriptionModel> Put([FromBody] List<SubscriptionModel> model)
{
// Receive a report of whether your subscription(s) was successfully added or not.
List<SubscriptionModel> subscriptions = new List<SubscriptionModel>();
foreach (SubscriptionModel m in model)
{
m.message = "Push notification successfully received.";
subscriptions.Add(m);
}
return subscriptions;
}
}
}
The only solution I can think of is to create another object which will just be for returning information; and applying each subscriptions item I want to send on to that.
You can't. You'd need another class. A "light" version that contains just the properties. Or you could do an anonymous type, but that is difficult to work with. I agree with the other guy on your naming conventions though :).

Categories